在Android的程序開發(fā)中碧磅,許多耗時(shí)操作都要放到子線程中例获,避免阻塞主線程杈抢,導(dǎo)致ANR神汹。但是在使用異步線程的過程中都會(huì)遇到與主線程通信的問題庆捺。
在這里先總體介紹幾種常見異步處理的技術(shù),以及他們的對(duì)應(yīng)關(guān)系:
Thread
使用Thread有兩種方式屁魏,一直是使用Thread滔以,一種是使用Runnable。
Thread方式:
public class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(0);
}
}
然后在使用的時(shí)候調(diào)用
new MyThread().start();
Runnable
public class MyRunnable implements Runnable{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(0);
}
}
使用的時(shí)候調(diào)用:
new Thread(new MyRunnable()).start();
總結(jié)
線程是執(zhí)行任務(wù)的最基本的單元氓拼,在Android開發(fā)中你画,線程又分為主線程和子線程,主線程中不能進(jìn)行耗時(shí)的操作桃漾,比如網(wǎng)絡(luò)請(qǐng)求坏匪,子線程中不能執(zhí)行更新UI的相關(guān)操作,否則都會(huì)拋出異常呈队。
根據(jù)上述例子可以看出剥槐,使用Thread執(zhí)行任務(wù),在結(jié)束后宪摧,需要通過Handler來發(fā)送消息粒竖,通知UI主線程,進(jìn)行對(duì)應(yīng)的界面更新几于。
HandlerThread
上面提到過Thread執(zhí)行完任務(wù)需要Handler來通知主線程蕊苗,HandlerThread集合了Thread和Handler,集成了Looper和MessageQueue沿彭。當(dāng)啟動(dòng)HandlerThread時(shí)朽砰,會(huì)同時(shí)生成Looper和MessageQueue,然后等待消息處理喉刘。
這里簡單寫一下:
private class myBackRunnable implements Runnable{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mainHandler.post(new myUIRunnable());
}
}
private class myUIRunnable implements Runnable{
@Override
public void run() {
btnStart.setText("線程結(jié)束");
}
}
啟動(dòng)子線程:
backHandler = new Handler(handlerThread.getLooper());
mainHandler = new Handler(getMainLooper());
backHandler.post(new myBackRunnable());
AsyncTask
AsyncTask提供了方便的接口實(shí)現(xiàn)工作線程和主線程的通信瞧柔,我這里先貼一下代碼,后面再根據(jù)代碼進(jìn)行解釋:
public class MyAsyncTask extends AsyncTask<Integer, String, String> {
private Button btn;
public MyAsyncTask(Button btn) {
super();
this.btn = btn;
}
@Override
protected String doInBackground(Integer... integers) {
Log.e("xxxxxx","xxxxxxexecute傳入?yún)?shù)="+integers[0]);
try {
Thread.sleep(1000);
publishProgress("過了一秒");
Thread.sleep(1000);
publishProgress("過了兩秒");
Thread.sleep(1000);
publishProgress("過了三秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "doInBackground的返回";
}
/**
* 這里的String參數(shù)對(duì)應(yīng)AsyncTask中的第三個(gè)參數(shù)(也就是接收doInBackground的返回值)
* 在doInBackground方法執(zhí)行結(jié)束之后在運(yùn)行睦裳,并且運(yùn)行在UI線程當(dāng)中 可以對(duì)UI空間進(jìn)行設(shè)置
*/
@Override
protected void onPostExecute(String result) {
btn.setText("線程結(jié)束" + result);
}
//該方法運(yùn)行在UI線程當(dāng)中,并且運(yùn)行在UI線程當(dāng)中 可以對(duì)UI空間進(jìn)行設(shè)置
@Override
protected void onPreExecute() {
btn.setText("開始執(zhí)行異步線程");
}
/**
* 這里的Intege參數(shù)對(duì)應(yīng)AsyncTask中的第二個(gè)參數(shù)
* 在doInBackground方法當(dāng)中造锅,,每次調(diào)用publishProgress方法都會(huì)觸發(fā)onProgressUpdate執(zhí)行
* onProgressUpdate是在UI線程中執(zhí)行廉邑,所有可以對(duì)UI空間進(jìn)行操作
*/
@Override
protected void onProgressUpdate(String... values) {
String vlaue = values[0]+"";
Log.e("xxxxxx","xxxxxx vlaue="+vlaue);
btn.setText(vlaue+"");
}
}
AsyncTask就是一個(gè)封裝過的后臺(tái)任務(wù)類哥蔚,顧名思義就是異步任務(wù)倒谷。
AsyncTask定義了三種泛型類型 Params,Progress和Result糙箍。
Params 啟動(dòng)任務(wù)執(zhí)行的輸入?yún)?shù)渤愁,比如HTTP請(qǐng)求的URL。
Progress 后臺(tái)任務(wù)執(zhí)行的百分比深夯。
Result 后臺(tái)執(zhí)行任務(wù)最終返回的結(jié)果抖格,比如String。
對(duì)應(yīng)到上面的demo就是Integer, String, String塌西。
doInBackground(Params…) 后臺(tái)執(zhí)行他挎,比較耗時(shí)的操作都可以放在這里。注意這里不能直接操作UI捡需。此方法在后臺(tái)線程執(zhí)行办桨,完成任務(wù)的主要工作,通常需要較長的時(shí)間站辉。在執(zhí)行過程中可以調(diào)用publicProgress(Progress…)來更新任務(wù)的進(jìn)度呢撞。
onProgressUpdate(String... Progress)這里對(duì)應(yīng)的是doInBackground中調(diào)用的publicProgress,在這里進(jìn)行處理饰剥,這里是UI主線程可以進(jìn)行界面的更新
onPreExecute()這里相當(dāng)于線程的開始殊霞,可以進(jìn)行UI的處理
onPostExecute(Result) 相當(dāng)于Handler 處理UI的方式,在這里面可以使用在doInBackground 得到的結(jié)果處理操作UI汰蓉。 此方法在主線程執(zhí)行绷蹲,任務(wù)執(zhí)行的結(jié)果作為此方法的參數(shù)返回。
我們?cè)賮砜匆幌氯绾伍_啟
myAsyncTask.execute(1000);
execute的參數(shù)對(duì)應(yīng)的就是上面提到過的Params顾孽。
IntentService
IntentService具有Service一樣的生命周期祝钢,也提供了后臺(tái)線程中的異步處理機(jī)制。還是先看一下代碼吧若厚。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("");
}
@Override
protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(3*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intentresult = new Intent(IntentServiceActivity.RESULT);
sendBroadcast(intentresult);
}
public void onDestroy()
{
super.onDestroy();
}
}
這里我們是通過廣播拦英,將結(jié)果返回到源Activity進(jìn)行界面更新的,這樣的處理方式感覺很重测秸,如非設(shè)計(jì)流程需要使用疤估,不建議經(jīng)常使用。
再看一下如何啟動(dòng):
Intent intent=new Intent(IntentServiceActivity.this,MyIntentService.class);
startService(intent);
其他
AsyncQueryHandler是用于在ContentProvider上面執(zhí)行異步操作的工具類霎冯,筆者自己也不常用铃拇,這里不再贅述。
Exector框架的基礎(chǔ)是一個(gè)名為Exector的接口定義沈撞,Exector的主要任務(wù)是分離任務(wù)的創(chuàng)建和他的執(zhí)行锚贱。這個(gè)我將在下一篇文章線程池相關(guān)的介紹中詳細(xì)描述。
上面介紹過的所有異步機(jī)制关串,我已經(jīng)整理出一個(gè)demo工程拧廊,方便開發(fā)者測試:
https://github.com/mymdeep/TestAsynchronous