Android的Handler

背景

知其然要知其所以然,為什么會有Handler的出現(xiàn)?舉個例子,假設我們在一個Thread中直接刷新某個TextView,并且每毫秒就刷新一次,那么TextView的繪制會瘋掉,而且用戶體驗也不好。所以為了控制UI的刷新頻率,Android規(guī)定非UI線程不能直接控制UI組件,只能通過Handler來處理。

概念解析

非UI線程計算出結(jié)果后,將結(jié)果封裝到Message里,調(diào)用Handler對象將消息放到MessageQueue消息隊列里,然后由Looper按照自己的節(jié)奏從隊列中取出消息,交給Handler對象的handleMessage方法處理。


image.png

實例化Message
通常使用Message類里的靜態(tài)方法obtain(),該方法有多個重載版本可供選擇;它的創(chuàng)建并不一定是直接創(chuàng)建一個新的實例,而是先從Message Pool(消息池)中看有沒有可用的Message實例,存在則直接取出返回這個實例。如果Message Pool中沒有可用的Message實例,則才用給定的參數(shù)創(chuàng)建一個Message對象。對于Message對象,一般并不推薦直接使用它的構(gòu)造方法得到,而是建議通過使用Message.obtain()這個靜態(tài)的方法或者Handler.obtainMessage()獲取。除了上面這種方式,也可以通過Handler對象的obtainMessage()獲取一個Message實例。
[圖片上傳失敗...(image-911b1-1533626470342)]

Message可以傳遞什么值
可以直接賦值一個對象給message.obj,直接賦值個flag給message.what(通常用于區(qū)分各個Message),也可以message.setData(bundle),而Bundle對象里可以放各種對象。

Handler對象發(fā)送定義好的Message
[圖片上傳失敗...(image-e6ba85-1533626470342)]

通過上圖可以看到,
sendEmptyMessage(int what):直接發(fā)送一個flag
sendEmptyMessageAtTime(int what,long uptimeMillis):指定時間發(fā)送
sendEmptyMessageDelayed(int what,long uptimeMillis):延遲發(fā)送
sendMessageAtFrontOfQueue(Message msg):把消息發(fā)到隊列前面

MessageQueue和Looper
Looper是MessageQueue(消息隊列)的管理者。主線程創(chuàng)建時,會創(chuàng)建一個默認的Looper對象,而Looper對象的創(chuàng)建,將自動創(chuàng)建一個MessageQueue。其他非主線程,不會自動創(chuàng)建Looper,要需要的時候,通過調(diào)用prepare函數(shù)來實現(xiàn)。

為什么Handler會引起的內(nèi)存溢出
1.Android App啟動的時候,Android Framework 為主線程創(chuàng)建一個Looper對象,這個Looper對象將貫穿這個App的整個生命周期,它實現(xiàn)了一個消息隊列(Message Queue),并且開啟一個循環(huán)來處理Message對象。而Framework的主要事件都包含著內(nèi)部Message對象,當這些事件被觸發(fā)的時候,Message對象會被加到消息隊列中執(zhí)行。
2.當一個 Handler被實例化時,它將和主線程Looper對象的消息隊列相關聯(lián),被推到消息隊列中的Message對象將持有一個 Handler的引用以便于當Looper處理到這個Message的時候,Framework執(zhí)行Handler的 handleMessage(Message)方法。
3.在 Java 語言中,非靜態(tài)匿名內(nèi)部類將持有一個對外部類的隱式引用,而靜態(tài)內(nèi)部類則不會。

當 Activity被finish()掉,Message將存在于消息隊列中長達10分鐘的時間才會被執(zhí)行到。這個Message持有一個對Handler的引用,Handler也會持有一個對于外部類 (SampleActivity)的隱式引用,這些引用在Message被執(zhí)行前將一直保持,這樣會導致Activity的上下文不被垃圾回收機制回收, 同時也會泄露應用程序的資源(views and resources)。
在實際開發(fā)中,如果內(nèi)部類的生命周期和Activity的生命周期不一致(比如上面那種,Activity finish()之后要等10分鐘,內(nèi)部類的實例才會執(zhí)行),則在Activity中要避免使用非靜態(tài)的內(nèi)部類,這種情況,就使用一個靜態(tài)內(nèi)部類,同時持有一個對Activity的WeakReference。

使用實例

//定義該類,使用WeakRefrence是為了防止內(nèi)存泄露
private static class MyHandler extends  Handler {

        private final WeakReference<OrderProFragment> mFragment;

        private MyHandler(OrderProFragment activity) {
            mFragment = new WeakReference<OrderProFragment>(activity);
        }
        @Override
        public void handleMessage(Message msg) {
            OrderProFragment fragment = mFragment.get();
            if(fragment!=null){
                fragment.handle(msg);
            }
        }
    };
    //定義處理消息方法
    private void handle(Message msg){
        if (msg.what == RUNNING) {
            baseShowLog("mHandler:RUNNING");
        } else if (msg.what == FINISH) {

            baseShowLog("mHandler:FINISH");
        }
    }

實例化該內(nèi)部類:

 MyHandler mMyHandler=new MyHandler(this);

在非UI線程中發(fā)送消息

private void outsideRun(){
    mPayLeftTime--;
    if (mPayLeftTime == 0) {
        mMyHandler.sendEmptyMessage(FINISH);
    } else if (mPayLeftTime > 0) {
        mMyHandler.sendEmptyMessage(RUNNING);
    }
}

最后別忘了

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

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

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