1. 程式人生 > >Android使用Handler實現子執行緒與子執行緒、主執行緒之間通訊

Android使用Handler實現子執行緒與子執行緒、主執行緒之間通訊

今天這篇文章只講一下怎麼使用Handler實現子執行緒與子執行緒之間、子執行緒與主執行緒之間如何進行通訊,關於具體的內部實現因為我也沒研究過,所以這篇文章講不了。

一、子執行緒向主執行緒傳值:

這個實現比較簡單,因為主執行緒自帶Looper機制,所有我們不用建立Looper了,看一下程式碼吧:

首選在主執行緒裡建立一個Handler

1.Handler mHandler = new Handler(){  
2.  
3.    @Override  
4.    public void handleMessage(Message msg) {  
5.        super.handleMessage(msg);  
6.        
switch (msg.what) { 7. case 0: 8. //do something,refresh UI; 9. break; 10. default: 11. break; 12. } 13. } 14. 15.};

然後開啟一個子執行緒,在子執行緒裡直接使用Handler傳送訊息即可

new Thread() {
            public void run() {
                Message message = new
Message(); message.obj = "子執行緒傳送的訊息Hi~Hi"; mHandler .sendMessage(message); }; }.start();

二、主執行緒向子執行緒裡傳送訊息:

主執行緒向子執行緒傳送訊息的話,我們需要在子執行緒裡初始化Looper,並在主執行緒裡建立的Handler引用子執行緒的Looper(Handler中引用的是哪個執行緒的Looper,就在哪個執行緒裡處理訊息),下面看程式碼:

 public class ThreadHandlerActivity
extends Activity{
//建立子執行緒 class MyThread extends Thread{ private Looper looper;//取出該子執行緒的Looper public void run() { Looper.prepare();//建立該子執行緒的Looper looper = Looper.myLooper();//取出該子執行緒的Looper Looper.loop();//只要呼叫了該方法才能不斷迴圈取出訊息 } } private Handler mHandler;//將mHandler指定輪詢的Looper protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); thread = new MyThread(); thread.start();//千萬別忘記開啟這個執行緒 //下面是主執行緒傳送訊息 mHandler = new Handler(thread.looper){ public void handleMessage(android.os.Message msg) { Log.d("當前子執行緒是----->",Thread.currentThread()+""); }; }; mHandler.sendEmptyMessage(1); } }

其實這樣就可以達到主執行緒向子執行緒傳送訊息了,然而當我們執行後發現程式會Crash掉,報了一個控制針,這是因為在Handler初始化的時候,thread.looper還沒有初始化,所以會報控制針,這時我們可以讓主執行緒等待一下子執行緒,也可以來一個while迴圈來判斷thread.looper是否初始化完成。不過Android本身還提供了一個方法,那就是HandlerThread

     protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             tv = new TextView(this);
             tv.setText("Handler實驗");
             setContentView(tv);

             //例項化一個特殊的執行緒HandlerThread,必須給其指定一個名字
            HandlerThread thread = new HandlerThread("handler thread");
             thread.start();//千萬不要忘記開啟這個執行緒
             //將mHandler與thread相關聯
             mHandler = new Handler(thread.getLooper()){
                 public void handleMessage(android.os.Message msg) {
                     Log.d("當前子執行緒是----->", Thread.currentThread()+"");
                 };
             };
             mHandler.sendEmptyMessage(1);//傳送訊息
     }

這時HandlerMessage所在的執行緒就是HandlerThread 的子執行緒。
然而HandlerThread 所建立處理的子執行緒裡是不能重寫Run()方法的,你寫了以後,會發現,HandlerMessage不執行了,這時因為HandlerMessage本身實現了Run()方法,我們看一下內部實現:

@Override
     public void run() {
         mTid = Process.myTid();
         Looper.prepare();
         synchronized (this) {
             mLooper = Looper.myLooper();
             notifyAll();
         }
         Process.setThreadPriority(mPriority);
         onLooperPrepared();
         Looper.loop();
         mTid = -1;
     }

在原始碼的第4行,進行了例項化自己的Looper,如果繼續追蹤原始碼翻看其getLooper方法你會發現,如果一個Handler在與HandlerThread進行繫結時,發現Looper為空,Handler則會一直等待直到Looper被創建出來為止,然後才繼續執行後續的程式碼。所以我們重寫了HandlerThread的run方法,肯定就不會去建立Looper物件,那麼繫結的Handler就會永遠處於等待狀態,自然而然就不會執行到HandlerMessage資訊了。這也是為什麼我們要使用HandlerThread這個特殊的執行緒,因為使用這個,我們不必關心多執行緒會混亂,Looper會為空等一系列問題,只要去關心我們要實現的邏輯就行了。

三、子執行緒和子執行緒之間通訊:

其實子執行緒向子執行緒之間通訊,其實就是在一個子執行緒中建立一個Handler,它的回撥自然就在此子執行緒中,然後在另一個子執行緒中呼叫此handler來發送訊息就可以了,不過記得寫上Looper哦,下面看程式碼:

new Thread(new Runnable() {

                      @Override
                      public void run() {
                          String msg;
                          Looper.prepare();

                          childHandler = new Handler() {
                              @Override
                    public void handleMessage(Message msg) {
                                 super.handleMessage(msg);

                                 System.out.println("這個訊息是從-->>" + msg.obj+ "過來的,在" + "btn的子執行緒當中" + "中執行的");

                             }

                         };  
                      Looper.loop();//開始輪循

                     }
                 }).start();

其中 Looper.prepare()和Looper.loop()一定不要忘了寫。

然後我們建立第二個子執行緒

new Thread(new Runnable() {

                      @Override
                      public void run() {
                         Looper loop = Looper.myLooper();
               Message msg = childHandler.obtainMessage();
                         msg.obj = "btn2當中子執行緒";
                         childHandler.sendMessage(msg);
                     }
                 }).start();