1. 程式人生 > >Android-執行緒通訊設計模式-Handler訊息模型

Android-執行緒通訊設計模式-Handler訊息模型

思考問題:

1) Android中的工作執行緒獲取資料以後如何傳遞給主執行緒?
例如:
例如工作執行緒通過網路下載一張圖片,通過主執行緒將圖片更新到頁面上。
所有的耗時操作在工作執行緒,工作執行緒不能操作UI
2) Android 中主執行緒的資料如何傳遞給工作執行緒?
例如:
主執行緒將要下載的檔案的名字傳遞給工作執行緒。
記住:工作執行緒是不能更新UI的
目的:儘量不要去阻塞主執行緒,安卓中的UI執行在主執行緒。
3)SendMessage與PostMessage的區別:
前者同步,後者非同步。
SendMessage傳送訊息後會等對方處理完這個訊息後才會繼續!
PostMessage則將訊息傳送出去後就會繼續!
所以注意,不要通過PostMessage傳遞臨時變數指標,應該很可能訊息被處理時該變數已經銷燬,這時訪問就會出錯
4)handleMessage與dispatchMessage處理訊息的區別?


handleMessage處理訊息在主執行緒中
dispatchMessage處理訊息相當新開了一個執行緒中

用SendMessage替換DispatchMessage不會有問題,但是效率沒有DispatchMessage高
但是用DispatchMessage替換SendMessage卻不行!

dispatchMessage是新開了一個執行緒,而sendMessage是在主執行緒,所以更新UI的時候報錯了,這也應證了安卓只能在主執行緒更新UI這一情況了。

Android中執行緒通訊底層訊息模型

Handler給哪個執行緒發訊息,就關聯哪個執行緒的looper(雙向關聯!)

注:此章是為了個人能更好的理解Android底層機制

Android中執行緒之間進行資料傳遞通常要藉助訊息模型,在這個訊息模型中會設計到如下幾個物件:

  • Message(訊息物件):資料的載體

  • MessageQueue(訊息佇列):儲存多個訊息物件

  • Looper(迭代器物件):迭代訊息佇列

  • Handler(訊息處理物件)傳送,處理訊息

執行緒通訊模型

簡單案例不涉及主執行緒與工作執行緒!


class Message{
    Object obj;

    @Override
    public String toString() {
        return "Message [obj="
+ obj + "]"; } } class MessageQueue{ private BlockingQueue<Message> queue= new ArrayBlockingQueue<>(10); public void put(Message msg){//放訊息 try{ queue.put(msg); }catch(Exception e){} } public Message take(){//取訊息 try { return queue.take(); } catch (Exception e) { e.printStackTrace(); return null; } } } class Looper{ private MessageQueue mq; //Looper關聯MessageQueue(MessageQueue的生命週期隨looper變化而變化,這是強聚合) //Looper關聯Handler(通過set等方法的是低聚合) //注:能從Looper中關聯Handler,也能從Handler中關聯looper,這是雙向關聯! private Handler handler; public void setHandler(Handler handler) { this.handler = handler; } public MessageQueue getMq() { return mq; } boolean flag=true; public Looper(){ mq=new MessageQueue();//強聚合(組合) } public void loop(){ while(flag){ //迭代訊息佇列 Message msg=mq.take(); //呼叫handler方法處理訊息 handler.handleMessage(msg); } } } class Handler{ //Hanlder關聯looper(has a),獲取訊息佇列 private Looper looper; public Handler(Looper looper){ this.looper=looper; looper.setHandler(this); } //Handler與Message的關係是use a public void sendMessage(Message msg){ //將訊息儲存到訊息佇列 looper.getMq().put(msg); } public void handleMessage(Message msg){ //處理訊息佇列中的訊息 System.out.println(msg); } } public class TestMsg { public static void main(String[] args) { //訊息物件 Message msg1=new Message(); msg1.obj="helloworld"; //迭代器物件(此物件建立時會建立訊息佇列) Looper looper=new Looper(); Handler h=new Handler(looper); h.sendMessage(msg1); Message msg2=new Message(); msg2.obj="gsd1504"; h.sendMessage(msg2); looper.loop(); } }

主執行緒與工作執行緒配合案例


class Message{
    Object obj;

    @Override
    public String toString() {
        return "Message [obj=" + obj + "]";
    }

}
class MessageQueue{
    private BlockingQueue<Message> queue=
    new ArrayBlockingQueue<>(10);
    public void put(Message msg){//放訊息
        try{
        queue.put(msg);
        }catch(Exception e){}
    }
    public Message take(){//取訊息
        try {
        return queue.take();
        } catch (Exception e) {
        e.printStackTrace();
        return null;
        }
    }
}
class Looper{
    private MessageQueue mq;
    private Handler handler;
    public void setHandler(Handler handler) {
        this.handler = handler;
    }
    public MessageQueue getMq() {
        return mq;
    }
    boolean flag=true;
    public Looper(){
        mq=new MessageQueue();//強聚合(組合)
    }
    public void loop(){
        while(flag){
           //迭代訊息佇列
            Message msg=mq.take();
           //呼叫handler方法處理訊息
            handler.handleMessage(msg);
        }
    }
}
class Handler{
    private Looper looper;
    public Handler(Looper looper){
        this.looper=looper;
        looper.setHandler(this);
    }
    public void sendMessage(Message msg){
        //將訊息儲存到訊息佇列
        looper.getMq().put(msg);
    }
    public void handleMessage(Message msg){
        //處理訊息佇列中的訊息
        System.out.println(msg);
    }
}
public class TestMsg {
    static Looper looper;
    /**主執行緒給工作執行緒發訊息*/
    public static void main(String[] args) {
        //訊息物件
        Message msg1=new Message();
        msg1.obj="helloworld";
        //迭代器物件(此物件建立時會建立訊息佇列)
        new Thread(){
            public void run() {
                //looper共享資料集加鎖
                synchronized (TestMsg.class) {
                  looper=new Looper();
                  TestMsg.class.notify();//類物件
                }
                looper.loop();
            };
        }.start();
        synchronized (TestMsg.class) {
//Hanlder關聯那個執行緒的looper,就給哪個執行緒發訊息
//也就是主執行緒給工作執行緒發訊息
    if(looper==null)try{TestMsg.class.wait();}catch(Exception e){}
            Handler h=new Handler(looper);
            h.sendMessage(msg1);
        }
    }
}
//給哪個執行緒發訊息就讓handler關聯哪個執行緒的looper

提取類封裝拿到looper案例
HandlerThread類:

public class HandlerThread extends Thread{

    Looper looper;
    @Override
    public void run() {
        synchronized (this) {
            looper=new Looper();
            this.notify();
        }
        looper.loop();
    }

    public Looper getLooper(){
        synchronized (this) {
            if(looper==null)
            try{this.wait();}catch(Exception e){e.printStackTrace();}
            return looper;
        }
    }
   //一個方法執行在哪個執行緒取決於此方法在哪個執行緒被呼叫的
}

TestMsg類


class Message{
    Object obj;

    @Override
    public String toString() {
        return "Message [obj=" + obj + "]";
    }

}
class MessageQueue{
    private BlockingQueue<Message> queue=
    new ArrayBlockingQueue<>(10);
    public void put(Message msg){//放訊息
        try{
        queue.put(msg);
        }catch(Exception e){}
    }
    public Message take(){//取訊息
        try {
        return queue.take();
        } catch (Exception e) {
        e.printStackTrace();
        return null;
        }
    }
}
class Looper{
    private MessageQueue mq;
    private Handler handler;
    public void setHandler(Handler handler) {
        this.handler = handler;
    }
    public MessageQueue getMq() {
        return mq;
    }
    boolean flag=true;
    public Looper(){
        mq=new MessageQueue();//強聚合(組合)
    }
    public void loop(){
        while(flag){
           //迭代訊息佇列
            Message msg=mq.take();
           //呼叫handler方法處理訊息
            handler.handleMessage(msg);
        }
    }
}
class Handler{
    private Looper looper;
    public Handler(Looper looper){
        this.looper=looper;
        looper.setHandler(this);
    }
    public void sendMessage(Message msg){
        //將訊息儲存到訊息佇列
        looper.getMq().put(msg);
    }
    public void handleMessage(Message msg){
        //處理訊息佇列中的訊息
        System.out.println(msg);
    }
}
public class TestMsg {
    /**主執行緒給工作執行緒發訊息*/
    public static void main(String[] args) {
        //訊息物件
        Message msg1=new Message();
        msg1.obj="helloworld";
        //迭代器物件(此物件建立時會建立訊息佇列)
        HandlerThread ht=new HandlerThread();
        ht.start();
        System.out.println("start");
        Handler h=new Handler(ht.getLooper());
        System.out.println("h="+h);
        h.sendMessage(msg1);

    }
}
//給哪個執行緒發訊息就讓handler關聯哪個執行緒的looper