處理線程中消息隊列的方法目前我知道的分爲種兩種。一種是線程自己帶有消息隊列,如主線程和handlerThread,主線程不說了。handlerThread繼承自thread但它與通常thread不一樣的地方是它有本身的消息隊列。而通常線程(指本身建立的線程)在默認狀況下沒有和它相關的消息隊列。要想使其有在運行消息隊列的線程中調用Looper.prepare();方法。而後調用Looper.loop();去讓消息隊列中的消息挨個執行。以下所示:java
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
由於線程默認狀況下是沒有本身的消息隊列的,因此若是在該線程的run()方法中新建handler後調用handler.post(runnable);程序會報錯。但在run方法外調用就沒事。由於thread類只是管理子線程的,其真正的子線程是在run方法中的。android
本身寫的例子以下:app
package com.example.handlerdemo; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.R.integer; import android.app.Activity; import android.view.Menu; import android.view.TextureView; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button start=(Button) findViewById(R.id.button1); TextView textView=(TextView) findViewById(R.id.textView1); start.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub Thread thread=new Thread(){ @Override public void run() { // TODO Auto-generated method stub Looper.prepare(); handler=new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); switch (msg.what) { case 1: System.out.println("thread name is"+" "+Thread.currentThread().getName()); break; } } }; handler.post(runnable); Looper.loop(); } }; thread.start(); } }); } Runnable runnable=new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println("這是runnable1"); handler.sendMessage(handler.obtainMessage(1)); } }; @Override protected void onDestroy() { // TODO Auto-generated method stub System.out.println("looper綁定的線程是"+Looper.myLooper().getThread().getName()); Looper.myLooper().quit(); super.onDestroy(); } }
其中onDestroy方法中結束looper有錯誤。其獲得的是主線程的名字。會報錯。疑問:在哪裏結束Looper。有待研究。歡迎留言賜教。ide
handleMessage中打印出來的線程的名字是本身定義出來的線程的名字。而非主線程。而onDestroy方法中打印出來的是主線程的名字。且該處錯誤,不應在此處中止looper,此處疑問。oop
接近一年後再次回來看本身曾經的疑問,感受那時本身好傻啊,這麼明顯的問題都沒看出來。哎,看來本身仍是進步了。竊喜。在onDestroy方法中中止的固然必須是當初的那個looper,而上文在onDestroy中quit的,是從新得到的當前線程(main)線程的looper,固然不是原來的,因此會報錯啊。須將本身聲明的線程中的Looper mLooper=Looper.myLooper();而後在onDestroy中直接mLooper.quit();就OK了。至於具體深刻研究還需去看源碼,加油吧,路上的孩子。post
其中handler的還能夠這樣生成:ui
handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// TODO Auto-generated method stub
switch (msg.what) {
case 1:
System.out.println("thread name is"+" "+Thread.currentThread().getName());
break;
}
return true;
}
});
spa
Callback接口是Handler的內部接口。用來實例化handler避免本身生成handler子類的麻煩。線程
須要注意的幾點code
1.Looper.prepare();和Looper.loop();都是在run方法中執行。
2.handler.post(runnable);必須寫在Looper.loop();方法前面,不然沒有效果。
3.在runnable中能夠屢次調用handler.sendMessage(handler.obtainMessage(1));只是Message.what值不一樣就能夠發送不一樣的消息。在handleMessage中handler就能夠根據what值對不一樣的消息分別處理。
4.不要忘記了調用thread.start();方法。
下面說說handlerThread,其自己帶有消息隊列因此就不要像通常線程那樣調用Looper.prepare等方法了。下面是例子代碼:
package com.example.handlerdemo2; import android.R.integer; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; public class MainActivity extends Activity { private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button=(Button) findViewById(R.id.button1); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub //參數爲線程的名字可經過getName返回。 HandlerThread handlerThread=new HandlerThread("handlerthread"); handlerThread.start(); Handler handler=new Handler(handlerThread.getLooper(),new Handler.Callback() { @Override public boolean handleMessage(Message msg) { // TODO Auto-generated method stub try { //經過讓線程休眠16秒沒有報錯,能夠驗證該是一個獨立於主線程的線程。能夠在此處理耗時操做。 Thread.sleep(16000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } switch (msg.what) { case 1: System.out.println("這是message1發來的消息"); //此處獲得的名字就是初始化handlerThread時裏面的參數 System.out.println("thread name is---->"+Thread.currentThread().getName()); break; case 2: System.out.println("這是message2發來的消息"); System.out.println("thread name is---->"+Thread.currentThread().getName()); break; } return true; } }); //能夠經過hanler獲得不一樣的Message從而在handleMessage方法中對消息進行分別處理。 Message message1=handler.obtainMessage(1); Message message2=handler.obtainMessage(2); message2.sendToTarget(); message1.sendToTarget(); } }); } }其就將對Looper的處理交由handlerThread處理了本身就不用管了,方便了一些。該方法中handler的聲明使該handler綁定到handlerthread的looper所在的消息隊列中去了。