Android的UI更新只能在UI線程中,即主線程。子線程中如果要進行UI更新,都是要通知主線程來進行。
幾種實現方式總結如下,歡迎補充。
1、runOnUiThread()
子線程中持有當前Activity引用(假如為Activity mActivity;),即可以調用mActivity的runOnUiThread(Runnable r)方法。
2、post()和postDelay()
子線程如果持有某個View的引用,要對該View進行更新,則可調用該View對象的post(Runnable r)或postDelay(Runnable r)方法
Handler對象也有post()方法。其實在Android的源碼中,這些post()方法都是借助下面的第3種方法:Handler + Message來實現的。
3、Handler + Message或者Handler + Thread + Message
主線程建立時,默認情況下是有Looper的,可以處理消息隊列。
在主線程建立一個Handler對象,復寫其handleMessage()方法,在該方法中實現UI更新。
示例:
private static final int MSG_CODE = 1001;
private Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
//接收並處理消息
if(msg.what == MSG_CODE)
{
//UI更新
}
}
};
public void doSomething()
{
new Thread()
{
@Override
public void run()
{
//子線程發送信息
Message msg = mHandler.obtainMessage(MSG_CODE);
msg.sendToTarget();
}
}.start();
}
4、Broadcast
子線程中發送廣播,主線程中接收廣播並更新UI
5、AsyncTask
AsyncTask可方便地實現新開一個線程,並將結果返回給UI線程,而不需要開發者手動去新開一個線程,也無須開發者使用Handler,非常方便。
應當注意的是AsyncTask是一個抽象類,其三個泛型參數的意義如下:
AsyncTask<Param, Progress, Result>
Param:發送給新開的線程的參數類型
Progress:表征任務處理進度的類型。
Result:線程任務處理完之后,返回給UI線程的值的類型。
該類中有四個抽象函數,onPreExecute(), doInBackground(Params... param),
onProgressUpdate(Progress... progress), onPostExecute(Result result)。
除了,doInBackground(Params...)方法,其它三個方法都運行在UI線程。
自定義一個類繼承AsyncTask並至少實現 doInBackground()函數。在該函數中執行的過程中,可以隨時調用publishProgress(Progress...)報告其執行進 度。此時會觸發另一個方法onProgressUpdate(Progress... progress),以便在UI線程中的某些控件(如ProgressBar)上更新任務處理的進度。
也可以等doInBackground()執行完,進入onPostExecute()方法后,再進行UI控件的更新。
可在任意時間,任意線程中,取消AsyncTask開啟的任務(調用自定義的AsynTask子類的cancel(boolean mayInterruptIfRunning)方法)
使用示例如下:
//如果沒記錯的話,這個例子應該是之前總結的時候從官網剪下來的
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}