android消息機(jī)制—Handler

在android日常開發(fā)中我們經(jīng)常會(huì)有從網(wǎng)上獲取數(shù)據(jù)更新UI的需求,但是Goole出于安全考慮規(guī)定,只有android主線程才能更新UI,涉及到耗時(shí)操作的要放到子線程中處理。不過Google也為我們?cè)O(shè)計(jì)了Handler用于將子線程中的數(shù)據(jù)更新到UI線程。

項(xiàng)目源碼

Handler的基本使用

在android中Handler主要用來(lái)接受和發(fā)送消息,他的基本使用如下:

//接受消息
@SuppressLint("HandlerLeak")
private Handler mHanlder = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 200:
               mTV_testHandler.setText((String) msg.obj);
            break;
        }
        super.handleMessage(msg);
    }
};

//在線程中發(fā)送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = new Message();
                msg.what = 200;
                msg.obj = "這是Send發(fā)送的消息";
                mHanlder.sendMessage(msg);
            }
        }).start();
    }
}).start();

子線程中能創(chuàng)建Handler嗎

因?yàn)閔andler在創(chuàng)建的時(shí)候必須綁定Looper,否則回報(bào)not called Looper.prepare()異常,因此在線程中不能直接使用Handler空參構(gòu)造方法;可以通過下面兩種方式解決

第一種方式

new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        Handler handler2 = new Handler();
        //一定要開啟循環(huán)
        Looper.loop();
    }
});

第二種方式

//傳入一個(gè)Looper
Handler handler2=new Handler(looper);

Handler如何與Looper關(guān)聯(lián)

Handler關(guān)聯(lián)Looper有兩種方式,一種是在構(gòu)造中傳入Looper,另外是在線程中調(diào)用Looper.perpare()。

//構(gòu)造1
public Handler() {
    this(null, false);
}
//構(gòu)造2
public Handler(Callback callback) {
    this(callback, false);
}
//構(gòu)造3
public Handler(Looper looper) {
    this(looper, null, false);
}
 //構(gòu)造4
public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
//構(gòu)造5
public Handler(boolean async) {
    this(null, async);
}
//構(gòu)造6
public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    //關(guān)聯(lián)Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    //獲取Looper中創(chuàng)建的MessageQueue
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
 //構(gòu)造7
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    //獲取Looper中創(chuàng)建的MessageQueue
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

Handler總共有六種構(gòu)造,其中構(gòu)造1、構(gòu)造2、構(gòu)造5他們的本質(zhì)都是調(diào)用了構(gòu)造6在該構(gòu)造中調(diào)用了Looper.myLooper()來(lái)關(guān)聯(lián)Looper,另外從上面的代碼中也可以知道構(gòu)造3、構(gòu)造4本質(zhì)上調(diào)用了是構(gòu)造7并且他們指定了關(guān)聯(lián)的Looper。

Handler如何發(fā)送消息

Handler發(fā)送消息本質(zhì)上有兩種方式:

第一種handler.sendXXX()

通過mHandler.sendXXX()這種方式最后都會(huì)調(diào)用sendMessageDelayed(),下面我們來(lái)分析一下它的代碼:

public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    //SystemClock.uptimeMillis()獲取的是從開機(jī)到現(xiàn)在的毫秒數(shù)
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

sendMessageDelayed的代碼也很簡(jiǎn)單,就是將消息和計(jì)算的從開機(jī)到現(xiàn)在的時(shí)間加上我們?cè)O(shè)置的延遲發(fā)送時(shí)間(如果沒有設(shè)置延遲時(shí)間默認(rèn)為0)作為參數(shù)調(diào)用
sendMessageAtTime()方法,最后這個(gè)方法會(huì)將從Looper中獲取的MessageQueue、消息和延遲時(shí)間傳入enqueueMessage()方法中:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    //將Hanlder賦值給Message的target
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //向MessageQueue插入消息
    return queue.enqueueMessage(msg, uptimeMillis);
}

第二種mHandler.postXXX()

通過mHandler.postXXX()這種方式其本質(zhì)和sendXXX()一樣也是最后調(diào)用了sendMessageAtTime()方法發(fā)送消息,他們兩個(gè)的區(qū)別是postXXX()方式要傳入一個(gè)Runnable,這個(gè)Runnable會(huì)被包裝成Message的callback。使用這種方式發(fā)消息比較方便一點(diǎn)。

//post發(fā)送消息
public final boolean post(Runnable r){
   return  sendMessageDelayed(getPostMessage(r), 0);
}
 //獲取Post發(fā)送方式的信息
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    //將post傳入的Runnable賦值給Message的callback變量
    m.callback = r;
    return m;
}

handler如何接收消息

handler的消息是Looper的loop()方法中調(diào)用 msg.target.dispatchMessage(msg);方法傳過來(lái)的,下面我們看看handler的dispatchMessage()方法。

public void dispatchMessage(Message msg) {
    //如果使用了postXXX方式發(fā)送消息,那么msg.callback就不會(huì)為空
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

當(dāng)程序執(zhí)行dispatchMessage()方法時(shí)會(huì)做如下操作,首先判斷Message的callback是否為空,如果不為空就會(huì)進(jìn)入該方法調(diào)用handleCallback(msg)如果為空就會(huì)做第二個(gè)判斷,即判斷Handler的mCallback是否為空,如果不為空就會(huì)執(zhí)行Callback的handleMessage()方法,如果這個(gè)函數(shù)返回true則跳出dispatchMessage(),否則就會(huì)執(zhí)行Handler的handleMessage(msg)方法。如果上面的判斷都不成立,那么系統(tǒng)將會(huì)調(diào)用Handler的handleMessage(msg)方法,該方法為一個(gè)空的函數(shù),需要開發(fā)者根據(jù)需求重寫該函數(shù),。看到這里可能會(huì)感覺有些亂,沒關(guān)系,下面我用三個(gè)例子來(lái)說(shuō)明。

1. msg.callback != null

我們?cè)谏厦鎝ostXXX()發(fā)送消息時(shí)候就提到過,postXXX()方法中的Runnable會(huì)被包裝成Message的callback,因此該消息在Handler的dispatchMessage()方法中msg.callback != null判斷成立,并且會(huì)調(diào)用handleCallback(msg)方法,該方法里面就一行代碼message.callback.run();即執(zhí)行postXXX()的Runnable對(duì)象的run()方法。

mHanlder.post(new Runnable() {
    @Override
    public void run() {
        mTV_testHandler.setText("這是Post發(fā)送的消息");
    }
});
2. mCallback != null

該方法是在創(chuàng)建Hanlder的時(shí)候在構(gòu)造函數(shù)中傳入Callback對(duì)象,Handler構(gòu)造中會(huì)將這個(gè)Callback對(duì)象賦值給Handler的mCallback,因此mCallback != null這個(gè)判斷成立。

Handler callbackHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case 202:
                //顯示消息
                mTV_testHandler.setText((String) msg.obj);
                break;
        }
        return false;
    }
});
//發(fā)送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = new Message();
                msg.what = 202;
                msg.obj = "這是Callback發(fā)送的消息";
                callbackHandler.sendMessage(msg);
            }
        }).start();
    }
}).start();
3. 執(zhí)行Hanlder的handleMessage(msg)

我們?cè)趧?chuàng)建Hanlder對(duì)象的時(shí)候,沒有傳入Callback對(duì)象,在發(fā)送消息的時(shí)候也沒有使用postXXX()的方式發(fā)送,因此上面兩中情況的判斷都不會(huì)成立,dispatchMessage()最后回到用Hanlder的空函數(shù)handleMessage()執(zhí)行里面的代碼。

@SuppressLint("HandlerLeak")
private Handler mHanlder = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 200:
                //顯示消息
                mTV_testHandler.setText((String) msg.obj);
                break;
        }
        super.handleMessage(msg);
    }
};

//發(fā)送消息
new Thread(new Runnable() {
    @Override
    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = new Message();
                msg.what = 200;
                msg.obj = "這是Send發(fā)送的消息";
                mHanlder.sendMessage(msg);
            }
        }).start();
    }
}).start();

參考:

你真的懂Handler嗎?Handler問答

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容