阿里二面的時候被問到這個問題,自己答的不全,所以總結下,問題是Android多線程中UI線程怎麼和其他線程進行交互?
5個方法:
1、handler
2、Activity.runOnUIThread(Runnable)
3、View.Post(Runnable)
4、View.PostDelayed(Runnabe,long)
5、AsyncTask
方法一:handler
假設A線程要傳遞信息給B線程,我們需要做的就是
1、在B線程中調用Looper.prepare和Looper.loop。(主線程不需要)
2、 編寫Handler類,重寫其中的handleMessage方法。
3、創建Handler類的實例,並綁定looper
4、調用handler的sentMessage方法發送消息。
1 public class MyHandlerActivity extends Activity {
2 TextView textView;
3 MyHandler myHandler;
4
5 protected void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.handlertest);
8
9 //實現創建handler並與looper綁定。這裏沒有涉及looper與
//線程的關聯是因爲主線程在創建之初就已有looper
10 myHandler=MyHandler(MyHandlerActivitythis.getMainLooper());
11 textView = (textView) findViewById(R.id.textView);
12
13 MyThread m = new MyThread();
14 new Thread(m).start();
15 }
16
17
18 class MyHandler extends Handler {
19 public MyHandler() {
20 }
21
22 public MyHandler(Looper L) {
23 super(L);
24 }
25
26 // 必須重寫這個方法,用於處理message
27 @Override
28 public void handleMessage(Message msg) {
29 // 這裏用於更新UI
30 Bundle b = msg.getData();
31 String color = b.getString("color");
32 MyHandlerActivity.this.textView.setText(color);
33 }
34 }
35
36 class MyThread implements Runnable {
37 public void run() {
38 //從消息池中取出一個message
39 Message msg = myHandler.obtainMessage();
40 //Bundle是message中的數據
41 Bundle b = new Bundle();
42 b.putString("color", "我的");
43 msg.setData(b);
44 //傳遞數據
45 myHandler.sendMessage(msg); // 向Handler發送消息,更新UI
46 }
47 }
方法二:Activity.runOnUIThread(Runnable)
1、編寫後臺線程,這回你可以直接調用UI控件
2、創建後臺線程的實例
3、調用UI線程對應的Activity的runOnUIThread方法,將後臺線程實例作爲參數傳入其中。
注意:無需調用後臺線程的start方法
方法三:View.Post(Runnable)
該方法和方法二基本相同,只是在後臺線程中能操控的UI控件被限制了,只能是指定的UI控件View。方法如下
1、編寫後臺線程,這回你可以直接調用UI控件,但是該UI控件只能是View
2、創建後臺線程的實例
3、調用UI控件View的post方法,將後臺線程實例作爲參數傳入其中。
方法四:View.PostDelayed(Runnabe,long)
該方法是方法三的補充,long參數用於制定多少時間後運行後臺進程
方法五:AsyncTask
AsyncTask是一個專門用來處理後臺進程與UI線程的工具。
AsyncTask擁有3個重要參數
1、Params
2、Progress
3、Result
Params是後臺線程所需的參數。在後臺線程進行作業的時候,他需要外界爲其提供必要的參數,就好像是一個用於下載圖片的後臺進程,他需要的參數就是圖片的下載地址。
Progress是後臺線程處理作業的進度。依舊上面的例子說,就是下載圖片這個任務完成了多少,是20%還是60%。這個數字是由Progress提供。
Result是後臺線程運行的結果,也就是需要提交給UI線程的信息。按照上面的例子來說,就是下載完成的圖片。
AsyncTask還擁有4個重要的回調方法。
1、onPreExecute
2、doInBackground
3、onProgressUpdate
4、onPostExecute
onPreExecute運行在UI線程,主要目的是爲後臺線程的運行做準備。當他運行完成後,他會調用doInBackground方法。
doInBackground運行在後臺線程,他用來負責運行任務。他擁有參數Params,並且返回Result。在後臺線程的運行當中,爲了能夠更新作業完成的進度,需要在doInbackground方法中調用PublishProgress方法。該方法擁有參數Progress。通過該方法可以更新Progress的數據。然後當調用完PublishProgress方法,他會調用onProgressUpdate方法用於更新進度。
onProgressUpdate運行在UI線程,主要目的是用來更新UI線程中顯示進度的UI控件。他擁有Progress參數。在doInBackground中調用PublishProgress之後,就會自動調onProgressUpdate方法
onPostExecute運行在UI線程,當doInBackground方法運行完後,他會調用onPostExecute方法,並傳入Result。在onPostExecute方法中,就可以將Result更新到UI控件上。
AsyncTask使用方法:
1、編寫一個繼承AsyncTask的類,並聲明3個參數的類型,編寫4個回調方法的內容。
2、然後在UI線程中創建該類(必須在UI線程中創建)。
3、最後調用AsyncTask的execute方法,傳入Parmas參數(同樣必須在UI線程中調用)。