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)系作者
  • 序言:七十年代末姐刁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子烦味,更是在濱河造成了極大的恐慌聂使,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬俄,死亡現(xiàn)場離奇詭異柏靶,居然都是意外死亡,警方通過查閱死者的電腦和手機溃论,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門屎蜓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钥勋,你說我怎么就攤上這事炬转。” “怎么了算灸?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵返吻,是天一觀的道長。 經(jīng)常有香客問我乎婿,道長,這世上最難降的妖魔是什么街佑? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任谢翎,我火速辦了婚禮捍靠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘森逮。我一直安慰自己榨婆,他們只是感情好,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布褒侧。 她就那樣靜靜地躺著良风,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闷供。 梳的紋絲不亂的頭發(fā)上烟央,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機與錄音歪脏,去河邊找鬼疑俭。 笑死,一個胖子當著我的面吹牛婿失,可吹牛的內(nèi)容都是我干的钞艇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼豪硅,長吁一口氣:“原來是場噩夢啊……” “哼哩照!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起懒浮,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤飘弧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嵌溢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眯牧,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年赖草,在試婚紗的時候發(fā)現(xiàn)自己被綠了学少。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡秧骑,死狀恐怖版确,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乎折,我是刑警寧澤绒疗,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站骂澄,受9級特大地震影響吓蘑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一磨镶、第九天 我趴在偏房一處隱蔽的房頂上張望溃蔫。 院中可真熱鬧,春花似錦琳猫、人聲如沸伟叛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽统刮。三九已至,卻和暖如春账千,著一層夾襖步出監(jiān)牢的瞬間侥蒙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工蕊爵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辉哥,地道東北人。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓攒射,卻偏偏與公主長得像醋旦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子会放,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容