1. 程式人生 > >理解Android的handler機制--從應用到原理再到實踐

理解Android的handler機制--從應用到原理再到實踐

關於Android的多執行緒機制,面試的時候總是問到,今天專門寫這個部落格,目的是把handler說清楚。

分別從下面四個方向說清楚。

 

由來

問題:為什麼有handler?

我們知道java是支援多執行緒的,而一個APP只有一個UI(即螢幕只有一個),如果每個執行緒都可以更新UI,呵呵,估計我們的APP就亂套了,所以Android的設計者就想著,更新UI只能在主執行緒中,子執行緒是不能更新UI的,子執行緒如果更新UI,系統就會丟擲異常。所以Android就需要提供一種機制,子執行緒通過這種機制可以在主執行緒中更新UI。

那麼java有沒有提供在子執行緒之間實時通訊的機制??? 由於執行緒的特性,一個程序內的所有執行緒夠共享同一儲存空間,即在多執行緒中,執行緒是可以訪問同一記憶體單元,這樣很可能出現數據不同步的問題,因此java提供了 synchronized關鍵字 和 Object 類的wait和notify方法(當然java還提供別的方法),但是此方法對Android更新UI這種特殊場合不是很適用。

因此Android專門提供了非同步訊息處理機制,用來解決在Android子執行緒中更新UI的操作。即handler機制。

 

應用

handler機制是為了在子執行緒中更新UI的,但是handler的作用不僅僅是為了更新UI的,準確的說是為了非同步訊息處理,因此從以下三種情況說明訊息是如何傳送和接受的。

子執行緒向主執行緒傳送訊息

Android是基於Java的,所以也分主執行緒,子執行緒!

(1)主執行緒:實現業務邏輯、UI繪製更新、各子執行緒串連,類似於將軍; 

(2)子執行緒:完成耗時(聯網取資料、SD卡資料載入、後臺長時間執行)操作,類似於小兵; 

對於使用者來說,程式碼預設執行在主執行緒中,子執行緒的程式碼在new thread內執行的程式碼。

第一步:在主執行緒中建立一個handler

    private Handler handler = new Handler() {

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT:
                    // 在這裡可以進行UI操作
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }

    };

第二步:開啟一個子執行緒,在子執行緒裡直接使用Handler傳送訊息即可

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        handler.sendMessage(message); // 將Message物件傳送出去
                    }
                }).start();

 

主執行緒向子執行緒傳送訊息

分兩種情況:

方法1在子執行緒裡初始化Looper

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

    //方法1
    public void method1(){
        thread = new MyThread();
        thread.start();//千萬別忘記開啟這個執行緒

        delay(1000);  //在Handler初始化的時候,thread.looper還沒有初始化,所以加一個延時

        handler1 = new Handler(thread.looper){
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case UPDATE:
                        // 在這裡可以進行UI操作
                        Log.d("當前子執行緒是--1--->",Thread.currentThread()+"");
                        break;
                    default:
                        break;
                }
            };
        };
    }


    //子執行緒
    class MyThread extends Thread{
        private Looper looper;//取出該子執行緒的Looper
        public void run() {
            Looper.prepare();//建立該子執行緒的Looper
            looper = Looper.myLooper();//取出該子執行緒的Looper
            Looper.loop();//只要呼叫了該方法才能不斷迴圈取出訊息
        }
    }

主執行緒傳送訊息:

//下面是主執行緒傳送訊息
Message message1 = new Message();
message1.what = UPDATE;
handler1.sendMessage(message1);
break;

這種方法有個確定,就是Handler初始化的時候,thread.looper還沒有初始化,會導致Crash。

方法2使用HandlerThread

Android提供了HandlerThread類,子執行緒中有handler,程式碼如下:

    //方法2
    public void method2(){
        //例項化一個特殊的執行緒HandlerThread,必須給其指定一個名字
        HandlerThread thread = new HandlerThread("handler thread");
        thread.start();//千萬不要忘記開啟這個執行緒
        //將mHandler與thread相關聯
        handler2 = new Handler(thread.getLooper()){
            public void handleMessage(android.os.Message msg) {
                switch (msg.what) {
                    case UPDATE:
                        // 在這裡可以進行UI操作
                        Log.d("當前子執行緒是--2--->",Thread.currentThread()+"");
                        break;
                    default:
                        break;
                }
            };
        };
    }

 

子執行緒向子執行緒傳送訊息

建立子執行緒,該子執行緒接受並處理訊息,(注意,該子執行緒的建立也可以應用上面的情況)

new Thread(new Runnable() {
	@Override
	public void run() {
		Looper.prepare();
		childHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				switch (msg.what) {
					case SEND:
						// 在這裡可以進行UI操作
						Log.d(TAG,"這個訊息是從-->>" + msg.obj + "過來的,在" + Thread.currentThread()+ "子執行緒當中執行的");
						break;
					default:
						break;
				}
			}

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

傳送訊息執行緒:

new Thread(new Runnable() {
	@Override
	public void run() {
		Message msg = childHandler.obtainMessage();
		msg.what = SEND;
		msg.obj =  ""+ Thread.currentThread();
		childHandler.sendMessage(msg);
	}
}).start();

以上分析主要參考Android使用Handler實現子執行緒與子執行緒、主執行緒之間通訊,但是這偏文章沒有寫好的原始碼,在總結這篇文章的基礎上,實現程式碼並上傳github,可直接下載執行。

 

原理

原理分析,主要檢視郭霖的《第一行程式碼,第二版》。

 

 

 

java實現

理解了handler機制後,我們可不可以用java手寫一個handler機制呢?