1. 為什么使用線程
android 的多線程實(shí)際上就是java的多線程。android的UI線程又稱為主線程洋腮。
我們創(chuàng)建的Service、Activity以及Broadcast均是一個(gè)主線程處理,這里我們可以理解為UI線程赞季。但是在操作一些耗時(shí)操作時(shí)现恼,比如I/O讀寫的大文件讀寫肃续,數(shù)據(jù)庫操作以及網(wǎng)絡(luò)下載需要很長(zhǎng)時(shí)間黍檩,為了不阻塞用戶界面,出現(xiàn)ANR的響應(yīng)提示窗口始锚,這個(gè)時(shí)候我們可以考慮使用Thread線程來解決刽酱。android 的多線程實(shí)際上就是java的多線程。android的UI線程又稱為主線程瞧捌。
我們創(chuàng)建的Service棵里、Activity以及Broadcast均是一個(gè)主線程處理,這里我們可以理解為UI線程察郁。但是在操作一些耗時(shí)操作時(shí)衍慎,比如I/O讀寫的大文件讀寫,數(shù)據(jù)庫操作以及網(wǎng)絡(luò)下載需要很長(zhǎng)時(shí)間皮钠,為了不阻塞用戶界面稳捆,出現(xiàn)ANR的響應(yīng)提示窗口,這個(gè)時(shí)候我們可以考慮使用Thread線程來解決麦轰。
2. Thread 和 Runnable
在java中可有兩種方式實(shí)現(xiàn)多線程乔夯,一種是繼承Thread類,一種是實(shí)現(xiàn)Runnable接口.
Thread類是在java.lang包中定義的款侵。一個(gè)類只要繼承了Thread類同時(shí)覆寫了本類中的run()方法就可以實(shí)現(xiàn)多線程操作了末荐,但是一個(gè)類只能繼承一個(gè)父類,這是此方法的局限新锈。所以甲脏,通常會(huì)實(shí)現(xiàn)Runnable接口方式。
Thread才是一個(gè)線程妹笆,而Runnable可以理解為一個(gè)任務(wù)块请。這個(gè)任務(wù)只是一個(gè)接口。具體的任務(wù)執(zhí)行是在 run()方法執(zhí)行拳缠,那么就是把一個(gè)Runnable任務(wù)放到線程里面墩新。當(dāng)調(diào)用thread.start() 的時(shí)候,系統(tǒng)新開一個(gè)線程去執(zhí)行窟坐,這個(gè)runnable任務(wù)是在多線程執(zhí)行的海渊。是在新開的線程執(zhí)行的。
注意以下兩種情況不能實(shí)現(xiàn)在工作線程執(zhí)行哲鸳,還是在UI線程執(zhí)行臣疑。
- thread.run() ,這樣子實(shí)際上只是在UI線程執(zhí)行了Runnable徙菠,并沒有實(shí)現(xiàn)多線程朝捆。系統(tǒng)也沒有新開一個(gè)線程。
- new Runnable().run()懒豹,那么實(shí)際上是直接在UI線程執(zhí)行了這個(gè)任務(wù)沒有進(jìn)行一個(gè)多線程的操作芙盘。
Thread使用的例子
Boolean isRun = true;
public void start_clicked(View v){
MyTread thread = new MyTread();
thread.start();
}
public void stop_clicked(View v){
isRun = false;
}
public class MyTread extends Thread{
@Override
public void run() {
int counter = 0;
while (isRun){
try {
Log.v("thread sample", String.valueOf(counter));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}
Runnable使用的例子
Boolean isRun = true;
public void start_clicked(View v){
MyTask task = new MyTask();
Thread thread = new Thread(task,"my thread");
thread.start();
}
public void stop_clicked(View v){
isRun = false;
}
public class MyTask implements Runnable {
@Override
public void run() {
int counter = 0;
while (isRun){
try {
Log.v("thread sample", String.valueOf(counter));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}
3. Handler
一驯用、Handler的定義:
Handler主要接收子線程發(fā)送的數(shù)據(jù), 并用此數(shù)據(jù)配合主線程更新UI,用來跟UI主線程交互用儒老。比如可以用handler發(fā)送一個(gè)message蝴乔,然后在handler的線程中來接收、處理該消息驮樊,以避免直接在UI主線程中處理事務(wù)導(dǎo)致影響UI主線程的其他處理工作薇正,Android提供了Handler作為主線程和子線程的紐帶;也可以將handler對(duì)象傳給其他進(jìn)程囚衔,以便在其他進(jìn)程中通過handler給你發(fā)送事件挖腰;還可以通過handler的延時(shí)發(fā)送message,可以延時(shí)處理一些事務(wù)的處理练湿。
通常情況下猴仑,當(dāng)應(yīng)用程序啟動(dòng)時(shí),Android首先會(huì)開啟一個(gè)主線程 (也就是UI線程) , 主線程為管理界面中的UI控件肥哎,進(jìn)行事件分發(fā)辽俗。如果此時(shí)需要一個(gè)耗時(shí)的操作,例如:聯(lián)網(wǎng)讀取數(shù)據(jù)篡诽,或者讀取本地較大的一個(gè)文件的時(shí)候崖飘,你不能把這些操作放在主線程中,如果你放在主線程中的話杈女,界面會(huì)出現(xiàn)假死現(xiàn)象,如果5秒鐘還沒有完成的話朱浴,會(huì)收到Android系統(tǒng)的一個(gè)錯(cuò)誤提示"強(qiáng)制關(guān)閉".
這個(gè)時(shí)候我們需要把這些耗時(shí)的操作,放在一個(gè)子線程中,因?yàn)樽泳€程涉及到UI更新达椰,但是當(dāng)子線程中有涉及到操作UI的操作時(shí)翰蠢,就會(huì)對(duì)主線程產(chǎn)生危險(xiǎn),也就是說砰碴,更新UI只能在主線程中更新躏筏,在子線程中操作是危險(xiǎn)的. 這個(gè)時(shí)候板丽,Handler就出現(xiàn)了來解決這個(gè)復(fù)雜的問題呈枉,由于Handler運(yùn)行在主線程中(UI線程中),它與子線程可以通過Message對(duì)象來傳遞數(shù)據(jù)埃碱,這個(gè)時(shí)候猖辫,Handler就承擔(dān)著接受子線程傳過來的(子線程用sedMessage()方法傳遞)Message對(duì)象,(里面包含數(shù)據(jù)), 把這些消息放入主線程隊(duì)列中砚殿,配合主線程進(jìn)行更新UI啃憎。
二、Handler一些特點(diǎn)
handler可以分發(fā)Message對(duì)象和Runnable對(duì)象到主線程中, 每個(gè)Handler實(shí)例,都會(huì)綁定到創(chuàng)建他的線程中(一般是位于主線程), 也就是說Handler對(duì)象初始化后似炎,就默認(rèn)與對(duì)它初始化的進(jìn)程的消息隊(duì)列綁定辛萍,因此可以利用Handler所包含的消息隊(duì)列悯姊,制定一些操作的順序。
三贩毕、Handler中分發(fā)消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
post類方法允許你排列一個(gè)Runnable對(duì)象到線程隊(duì)列中
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
sendMessage類方法, 允許你安排一個(gè)帶數(shù)據(jù)的Message對(duì)象到隊(duì)列中悯许,等待更新.
四、應(yīng)用實(shí)例:
1辉阶,sendMessage
一先壕、用于接受子線程發(fā)送的數(shù)據(jù), 并用此數(shù)據(jù)配合主線程更新UI
在Android中,對(duì)于UI的操作通常需要放在主線程中進(jìn)行操作谆甜。如果在子線程中有關(guān)于UI的操作垃僚,那么就需要把數(shù)據(jù)消息作為一個(gè)Message對(duì)象發(fā)送到消息隊(duì)列中,然后规辱,用Handler中的handlerMessge方法處理傳過來的數(shù)據(jù)信息谆棺,并操作UI。類sendMessage(Message msg)方法實(shí)現(xiàn)發(fā)送消息的操作按摘。 在初始化Handler對(duì)象時(shí)重寫的handleMessage方法來接收Messgae并進(jìn)行相關(guān)操作包券。

public void start_clicked(View v){
new Thread(new Runnable() {
@Override
public void run() {
int counter = 0;
while (isRun){
try {
Log.v("thread sample", String.valueOf(counter));
// send message to UI thread
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("counter", counter);
msg.setData(b);
mHandler.sendMessage(msg);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}).start();
}
public void stop_clicked(View v){
isRun = false;
}
Handler mHandler = new Handler(){
// handler 在UI線程創(chuàng)建,所以可以更新UI
public void handleMessage(android.os.Message msg) {
super.handleMessage(msg);
Bundle b = msg.getData();
int c = b.getInt("counter");
mInfo.setText(String.valueOf(c));
}
};
有一點(diǎn)需要注意炫贤,在獲得message實(shí)例有兩種辦法
//第一種
Message msg = new Message();
msg.what = xxx;
msg.arg1 = xxx;
msg.arg2 = xxx;
handler.sendMessage(msg);
//第一種
Message msg = handler.obtainMessage();
msg.what = xxx;
msg.arg1 = xxx;
msg.arg2 = xxx;
msg.obj = xxx;
msg.sendToTarget();
盡量使用第二種方法
原因:
- Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
- creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
- If you don't want that facility, just call Message.obtain() instead.
這里我們的Message 已經(jīng)不是 自己創(chuàng)建的了,而是從MessagePool 拿的,省去了創(chuàng)建對(duì)象申請(qǐng)內(nèi)存的開銷溅固。。兰珍。侍郭。。
二掠河、傳遞Message亮元。用戶UI線程向工作線程發(fā)送消息或者線程之間通信
Handler mThreadHandler;
public void start_clicked(View v){ //啟動(dòng)線程
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();// 創(chuàng)建該線程的Looper對(duì)象,用于接收消息,在非主線程中是沒有l(wèi)ooper的所以在創(chuàng)建handler前一定要使用prepare()創(chuàng)建一個(gè)Looper
mThreadHandler = new Handler() { // mThreadHandler 在工作線程創(chuàng)建唠摹,不可以更新UI
public void handleMessage(Message msg) {
// 耗時(shí)操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 結(jié)束完耗時(shí)操作 通知UI線程更新UI
Message msgToUI = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("counter", 5000);
msgToUI.setData(b);
mHandler.sendMessage(msgToUI);
}
};
Looper.loop();//建立一個(gè)消息循環(huán)爆捞,該線程不會(huì)退出
}
}).start();
}
public void stop_clicked(View v){
mThreadHandler.getLooper().quit(); //使用完成要停止looper,釋放線程
}
public void sendMessageToThread_clicked(View v) {
// UI線程向工作線程通過 mThreadHandler向工作線程發(fā)送sendMessage
mThreadHandler.sendEmptyMessage(0);
}
Handler mHandler = new Handler(){
// handler 在UI線程創(chuàng)建勾拉,所以可以更新UI
public void handleMessage(android.os.Message msg) {
//super.handleMessage(msg);
Bundle b = msg.getData();
int c = b.getInt("counter");
mInfo.setText(String.valueOf(c));
}
};
Looper類說明
Looper 類用來為一個(gè)線程跑一個(gè)消息循環(huán)煮甥。
線程在默認(rèn)情況下是沒有消息循環(huán)與之關(guān)聯(lián)的,Thread類在run()方法中的內(nèi)容執(zhí)行完之后就退出了藕赞,即線程做完自己的工作之后就結(jié)束了成肘,沒有循環(huán)的概念。
調(diào)用Looper類的 prepare() 方法可以為當(dāng)前線程創(chuàng)建一個(gè)消息循環(huán)斧蜕,調(diào)用loop() 方法使之處理信息双霍,直到循環(huán)結(jié)束。
Looper:
public void startThread_clicked(View v){
//簡(jiǎn)寫Runnable方式
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();// 創(chuàng)建該線程的Looper對(duì)象,用于接收消息,在非主線程中是沒有l(wèi)ooper的所以在創(chuàng)建handler前一定要使用prepare()創(chuàng)建一個(gè)Looper
mThreadHandler = new Handler() { // mThreadHandler 在工作線程創(chuàng)建
public void handleMessage(Message msg) {
// 耗時(shí)操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 結(jié)束完耗時(shí)操作 通知UI線程更新UI
Message msgToUI = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("counter", 5000);
msgToUI.setData(b);
mHandler.sendMessage(msgToUI);
}
};
Looper.loop();//建立一個(gè)消息循環(huán)洒闸,該線程不會(huì)退出
}
}).start();
}
public void sendMessageToThread_clicked(View v) {
// UI線程向工作線程通過 mThreadHandler向工作線程發(fā)送sendMessage
mThreadHandler.sendEmptyMessage(0);
}
public void stopThread_clicked(View v){
mThreadHandler.getLooper().quit(); //使用完成要停到looper染坯,釋放線程
}
HandlerThread:
我們實(shí)現(xiàn)Looper有沒有更加簡(jiǎn)單的方法呢?當(dāng)然有,這就是我們的HandlerThread丘逸。我們來看下Android對(duì)HandlerThread的描述:
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.
上面的工作線程代碼可以簡(jiǎn)化成
HandlerThread handlerThread = new HandlerThread("xxx");
handlerThread.start(); //創(chuàng)建HandlerThread后一定要記得start()
mThreadHandler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//耗時(shí)操作
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 結(jié)束完耗時(shí)操作 通知UI線程更新UI
Message msgToUI = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putInt("counter", 5000);
msgToUI.setData(b);
mHandler.sendMessage(msgToUI);
super.handleMessage(msg);
}
};
public void sendMessageToThread_clicked(View v) {
// UI線程向工作線程通過 mThreadHandler向工作線程發(fā)送sendMessage
mThreadHandler.sendEmptyMessage(0);
}
public void stopThread_clicked(View v){
mThreadHandler.getLooper().quit(); //使用完成要停到looper酒请,釋放線程
}
2,Post
除了上述的使用Handler發(fā)送以及處理消息外鸣个,handler還有一個(gè)作用就是處理傳遞給它的action對(duì)象羞反,具體使用步驟示例:
1、在主線程中定義Handler對(duì)象
2囤萤、構(gòu)造一個(gè)runnable對(duì)象昼窗,為該對(duì)象實(shí)現(xiàn)runnable方法。
3涛舍、在子線程中使用Handler對(duì)象post(runnable)對(duì)象.
handler.post這個(gè)函數(shù)的作用是把Runnable里面的run方法里面的這段代碼發(fā)送到消息隊(duì)列中澄惊,等待運(yùn)行。
如果handler是以UI線程消息隊(duì)列為參數(shù)構(gòu)造的富雅,那么是把run里面的代碼發(fā)送到UI線程中掸驱,等待UI線程運(yùn)行這段代碼。
如果handler是以子線程線程消息隊(duì)列為參數(shù)構(gòu)造的没佑,那么是把run里面的代碼發(fā)送到子線程中毕贼,等待子線程運(yùn)行這段代碼。
//延遲5秒 向UI線程消息隊(duì)列發(fā)送一條任務(wù)(Runnable)
public void start_clicked(View v){
Handler h = new Handler(this.getMainLooper());
h.postDelayed(new Runnable() {
@Override
public void run() {
mInfo.setText("Come from postDelayed");
}
}, 5000);
}
4. synchronized
一蛤奢、當(dāng)兩個(gè)并發(fā)線程訪問同一個(gè)對(duì)象object中的這個(gè)synchronized(this)同步代碼塊時(shí)鬼癣,一個(gè)時(shí)間內(nèi)只能有一個(gè)線程得到執(zhí)行。另一個(gè)線程必須等待當(dāng)前線程執(zhí)行完這個(gè)代碼塊以后才能執(zhí)行該代碼塊啤贩。
二待秃、然而,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí)痹屹,另一個(gè)線程仍然可以訪問該object中的非synchronized(this)同步代碼塊章郁。
三、尤其關(guān)鍵的是志衍,當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí)暖庄,其他線程對(duì)object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
四足画、當(dāng)一個(gè)線程訪問object的一個(gè)synchronized(this)同步代碼塊時(shí)雄驹,它就獲得了這個(gè)object的對(duì)象鎖佃牛。結(jié)果淹辞,其它線程對(duì)該object對(duì)象所有同步代碼部分的訪問都被暫時(shí)阻塞。
public void start_clicked(View v){
synchronizedTask task = new synchronizedTask();
new Thread(task,"A").start();
new Thread(task,"B").start();
}
public class synchronizedTask implements Runnable {
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
}
不加synchronized (this) 輸出為
System.out﹕ A
System.out﹕ B
System.out﹕ A
System.out﹕ B
System.out﹕ A
System.out﹕ B
System.out﹕ A
System.out﹕ B
System.out﹕ A
System.out﹕ B
synchronized (this) 輸出為
System.out﹕ A
System.out﹕ A
System.out﹕ A
System.out﹕ A
System.out﹕ A
System.out﹕ B
System.out﹕ B
System.out﹕ B
System.out﹕ B
System.out﹕ B
wait、notify象缀、notifyall蔬将、synchronized的使用機(jī)制:
synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
當(dāng)線程A獲得了obj鎖后,發(fā)現(xiàn)條件condition不滿足央星,無法繼續(xù)下一處理霞怀,于是線程A就wait() , 放棄對(duì)象鎖.
之后在另一線程B中,如果B更改了某些條件莉给,使得線程A的condition條件滿足了毙石,就可以喚醒線程A:
synchronized(obj) {
condition = true;
obj.notify();
}
需要注意的概念是:
調(diào)用obj的wait(), notify()方法前,必須獲得obj鎖颓遏,也就是必須寫在synchronized(obj) {…} 代碼段內(nèi)徐矩。
調(diào)用obj.wait()后,線程A就釋放了obj的鎖叁幢,否則線程B無法獲得obj鎖滤灯,也就無法在synchronized(obj) {…} 代碼段內(nèi)喚醒A。
當(dāng)obj.wait()方法返回后曼玩,線程A需要再次獲得obj鎖鳞骤,才能繼續(xù)執(zhí)行。
如果A1,A2,A3都在obj.wait()黍判,則B調(diào)用obj.notify()只能喚醒A1,A2,A3中的一個(gè)(具體哪一個(gè)由JVM決定)豫尽。
obj.notifyAll()則能全部喚醒A1,A2,A3,但是要繼續(xù)執(zhí)行obj.wait()的下一條語句顷帖,必須獲得obj鎖拂募,因此,A1,A2,A3只有一個(gè)有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行窟她,例如A1陈症,其余的需要等待A1釋放obj鎖之后才能繼續(xù)執(zhí)行。
當(dāng)B調(diào)用obj.notify/notifyAll的時(shí)候震糖,B正持有obj鎖录肯,因此,A1,A2,A3雖被喚醒吊说,但是仍無法獲得obj鎖论咏。直到B退出synchronized塊,釋放obj鎖后颁井,A1,A2,A3中的一個(gè)才有機(jī)會(huì)獲得鎖繼續(xù)執(zhí)行
5. AsyncTask
在Android中實(shí)現(xiàn)異步任務(wù)機(jī)制有兩種方式厅贪,Handler和AsyncTask。
Handler模式需要為每一個(gè)任務(wù)創(chuàng)建一個(gè)新的線程雅宾,任務(wù)完成后通過Handler實(shí)例向UI線程發(fā)送消息养涮,完成界面的更新,這種方式對(duì)于整個(gè)過程的控制比較精細(xì),但也是有缺點(diǎn)的贯吓,例如代碼相對(duì)臃腫懈凹,在多個(gè)任務(wù)同時(shí)執(zhí)行時(shí),不易對(duì)線程進(jìn)行精確的控制悄谐。關(guān)于Handler的相關(guān)知識(shí)介评,前面也有所介紹。
為了簡(jiǎn)化操作爬舰,Android1.5提供了工具類android.os.AsyncTask们陆,它使創(chuàng)建異步任務(wù)變得更加簡(jiǎn)單,不再需要編寫任務(wù)線程和Handler實(shí)例即可完成相同的任務(wù)情屹。
先來看看AsyncTask的定義:
public abstract class AsyncTask<Params, Progress, Result> {
三種泛型類型分別代表“啟動(dòng)任務(wù)執(zhí)行的輸入?yún)?shù)”棒掠、“后臺(tái)任務(wù)執(zhí)行的進(jìn)度”、“后臺(tái)計(jì)算結(jié)果的類型”屁商。在特定場(chǎng)合下烟很,并不是所有類型都被使用,如果沒有被使用蜡镶,可以用java.lang.Void類型代替雾袱。
一個(gè)異步任務(wù)的執(zhí)行一般包括以下幾個(gè)步驟:
1.execute(Params... params),執(zhí)行一個(gè)異步任務(wù)官还,需要我們?cè)诖a中調(diào)用此方法芹橡,觸發(fā)異步任務(wù)的執(zhí)行。
2.onPreExecute()望伦,在execute(Params... params)被調(diào)用后立即執(zhí)行林说,一般用來在執(zhí)行后臺(tái)任務(wù)前對(duì)UI做一些標(biāo)記。
3.doInBackground(Params... params)屯伞,在onPreExecute()完成后立即執(zhí)行腿箩,用于執(zhí)行較為費(fèi)時(shí)的操作,此方法將接收輸入?yún)?shù)和返回計(jì)算結(jié)果劣摇。在執(zhí)行過程中可以調(diào)用publishProgress(Progress... values)來更新進(jìn)度信息珠移。
4.onProgressUpdate(Progress... values),在調(diào)用publishProgress(Progress... values)時(shí)末融,此方法被執(zhí)行钧惧,直接將進(jìn)度信息更新到UI組件上。
5.onPostExecute(Result result)勾习,當(dāng)后臺(tái)操作結(jié)束時(shí)浓瞪,此方法將會(huì)被調(diào)用,計(jì)算結(jié)果將做為參數(shù)傳遞到此方法中巧婶,直接將結(jié)果顯示到UI組件上乾颁。
在使用的時(shí)候涂乌,有幾點(diǎn)需要格外注意:
1.異步任務(wù)的實(shí)例必須在UI線程中創(chuàng)建。
2.execute(Params... params)方法必須在UI線程中調(diào)用钮孵。
3.不要手動(dòng)調(diào)用onPreExecute(),doInBackground(Params... params)眼滤,onProgressUpdate(Progress... values)巴席,onPostExecute(Result result)這幾個(gè)方法。
4.不能在doInBackground(Params... params)中更改UI組件的信息诅需。
5.一個(gè)任務(wù)實(shí)例只能執(zhí)行一次漾唉,如果執(zhí)行第二次將會(huì)拋出異常。
private TextView mAsyncTaskInfo;
private ProgressBar mProgress;
private MyAsyncTask mTask;
public void asyncTask_clicked(View v){
mTask = new MyAsyncTask();
mTask.execute("demo");
}
public void cancel_asyncTask_clicked(View v){
mTask.cancel(true);
}
public class MyAsyncTask extends AsyncTask<String, Integer, String>{
//在execute(Params... params)被調(diào)用后立即執(zhí)行
//onPreExecute方法用于在執(zhí)行后臺(tái)任務(wù)前做一些UI操作
@Override
protected void onPreExecute() {
mAsyncTaskInfo.setText("loading...");
}
//onPreExecute()完成后立即執(zhí)行
//doInBackground方法內(nèi)部執(zhí)行后臺(tái)任務(wù),不可在此方法內(nèi)修改UI
@Override
protected String doInBackground(String... params) {
try {
if(params[0].equals("demo")){
Thread.sleep(2000);
while (counter < 100){
publishProgress(counter);
Thread.sleep(50);
counter++;
}
return "finished : " + String.valueOf(counter);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
//在調(diào)用publishProgress(Progress... values)時(shí)堰塌,此方法被執(zhí)行
//onProgressUpdate方法用于更新進(jìn)度信息
@Override
protected void onProgressUpdate(Integer... progresses) {
mProgress.setProgress(progresses[0]);
mAsyncTaskInfo.setText("loading..." + progresses[0] + "%");
}
//onPostExecute方法用于在執(zhí)行完后臺(tái)任務(wù)后更新UI,顯示結(jié)果
@Override
protected void onPostExecute(String result) {
mAsyncTaskInfo.setText(result);
}
//onCancelled方法用于在取消執(zhí)行中的任務(wù)時(shí)更改UI
@Override
protected void onCancelled() {
mAsyncTaskInfo.setText("cancelled");
mProgress.setProgress(0);
}
}
完赵刑!