Android 談談 Handler 那些事

轉(zhuǎn)載請注明出處
作者:developerHaoz
Github 地址:developerHaoz

本文的主要內(nèi)容

  • Handler 是什么
  • Handler 的兩個體系
  • Message

一胡岔、Handler是什么

Handler 是 Android 中引入的一種讓開發(fā)者參與處理線程中消息循環(huán)的機制责静,Handler直接繼承自 Object践磅,每個 Handler 都關聯(lián)了一個線程龄糊,每個線程內(nèi)部都維護了一個消息隊列 MessageQueue,這樣 Handler 實際上也就關聯(lián)了一個消息隊列日丹。這樣就可以通過 Handler 將 Message 和 Runnable 對象發(fā)送到該Handler所關聯(lián)線程的 MessageQueue(消息隊列)中,然后該消息隊列一直在循環(huán)拿出一個 Message,對其進行處理壳炎,處理完之后拿出下一個 Message,繼續(xù)處理

Handler 可以用來在多線程之間進行通信逼侦,在另一個線程中去更新 UI 線程中的 UI 控件只是 Handler 使用中的一種典型案例匿辩,除此之外,Handler 還可以做其他很多的事情榛丢,Handler 是 Thread 的代言人铲球,是多線程之間通信的橋梁,通過 Handler晰赞,我們可以在一個線程中控制另一個線程去做某些事

二稼病、Handler的兩個體系

Handler 可以把一個 Message 對象或者 Runnable 對象壓入到消息隊列中,進而在UI線程中獲取Message 或者執(zhí)行 Runnable 對象掖鱼,Handler 壓入消息隊列有兩大體系然走,Post 和 sendMessage

  • Post:Post允許把一個 Runnable 對象入隊到消息隊列中,它的方法有:post(Runnable)锨用、PostAtTime(Runnable, long)丰刊、postDelayed(Runnable, long)
  • sendMessage:sendMessage允許把一個包含消息數(shù)據(jù)的Message對象壓入到消息隊列中,它的方法有sendEmptyMessage(int)增拥、sendMessage(Message)啄巧、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)

從上面的各種方法可以看出掌栅,不管是 post 還是 sendMessage 都具有多種方法秩仆,它們可以設定Runnable 對象和 Message 對象被入隊到消息隊列中,是立即執(zhí)行還是延遲執(zhí)行

1猾封、Post

對于 Handler 的 Post 方式來說澄耍,它會傳遞一個 Runnable 對象到消息隊列中,在這個 Runnable 對象中晌缘,重寫 run() 方法齐莲,一般是在這個 run() 方法中寫入需要在UI線程中的操作

在 Handler 中,關于 Post 方式的方法有

方法名稱 作用
boolean post(Runnable r) 把一個 Runnabled 入隊到消息隊列中磷箕,UI 線程從消息隊列中取出這個對象后选酗,立即執(zhí)行
boolean postAtTime(Runnable r, long uptimeMills) 把一個 Runnable 入隊到消息隊列中,UI線程從消息獨立列中取出這個對象后岳枷,在特定的時間執(zhí)行
boolean postDelayed(Runnable r, long delayMills) 把一個 Runnable 入隊到消息隊列中芒填,UI線程從消息隊列中能夠取出這個對象后呜叫,延遲delayMills秒執(zhí)行
void removeCallbacks(Runnable r) 從消息隊列中移除一個 Runnable 對象

示例代碼

public void onClick() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                  // 將TextView的內(nèi)容進行修改
                    mTvShowInfo.setText("This is a test");
                }
            });
        }
    }).start();
}

有一點需要注意的是,對于 Post 方式而言殿衰,它其中的 Runnable 對象的 run() 方法的代碼朱庆,均執(zhí)行在UI線程上,所以如果是不能在 UI 線程上執(zhí)行的操作闷祥,如網(wǎng)絡請求之類的娱颊,一樣無法使用Post方式執(zhí)行

2、sendMessage

在Handler中蜀踏,與Message發(fā)送消息相關的方法

方法 作用
Message obtainMessage() 獲取一個Message對象
boolean sendMessage() 發(fā)送一個Message對象到消息隊列中维蒙,并在UI線程取到消息之后掰吕,立即執(zhí)行
boolean sendMessageDelayed() 發(fā)送一個Message對象到消息隊列中果覆,在 UI 線程取到消息后,延遲執(zhí)行
boolean sendEmptyMessage(int what) 發(fā)送一個空Message對象到消息隊列中殖熟,并在 UI 線程取到消息之后局待,立即執(zhí)行
boolean sendEmptyMessageDelayed(int what) 發(fā)送一個空Message對象到消息隊列中,并在 UI 線程取到消息之后菱属,延遲執(zhí)行
void removeMessage() 從消息隊列中移除一個未響應的消息

示例代碼

        new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        String testStr = "This is a test";
                        Message message = Message.obtain();
                        message.obj = testStr;
                        mHandler.sendMessage(message);
                    }
                });
            }
        }).start();
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == RESULT_OK_HANDLER) {
                String infoStr = (String)msg.obj;
                mHandlerTvShowInfo.setText(infoStr);
            }
        }
    };

三钳榨、Message

Handler 如果使用 sendMessage 的方式把消息入隊到消息隊列中,需要傳遞一個 Message 對象纽门,而在 Handler薛耻,需要重寫 handleMessage() 方法,用于獲取工作線程中傳遞過來的消息赏陵,此方法運行在 UI 線程上

1饼齿、獲取一個 Message 對象

一般并不推薦直接使用它的構(gòu)造方法得到,而是建議通過 Message.obtain() 這個靜態(tài)方法或者 Handler.obtainMessage() 獲取蝙搔。Message.obtain() 會從消息池中獲取一個 Message 對象缕溉,如果消息池是空的,才會使用構(gòu)造方法實例化一個新的 Message吃型,這樣有利用消息資源的重復利用证鸥,消息的上限為10個,Handler.obtainMessage() 具有多個重載方法勤晚,查看源碼可以知道枉层,Handler.obtainMessage() 在內(nèi)部其實也是調(diào)用 Message.obtain()

    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

2、設置赐写、獲取和傳遞數(shù)據(jù)

Message是一個 final 類鸟蜡,所以不可被繼承,Message 封裝了線程中傳遞過來的消息血淌,如果對于一般的數(shù)據(jù)矩欠,Message 提供了 getData() 和 setData 方法來獲取和設置數(shù)據(jù)财剖,其中操作的數(shù)據(jù)是一個Bundle 對象,這個 Bundle 對象提供一系列的 getXxx() 和 setXxx() 方法用于傳遞基本數(shù)據(jù)類型的鍵值對,使用起來比較簡單癌淮。

示例代碼

new Thread(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        String testStr = "This is a test";
                        Message message = Message.obtain();
                        Bundle testBundle = new Bundle();
                        testBundle.putString(KEY_STRING, testStr);
                        message.setData(testBundle);
                        message.what = RESULT_OK_HANDLER;
                        mHandler.sendMessage(message);
                    }
                });
            }
        }).start();
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == RESULT_OK_HANDLER) {
                String infoStr = msg.getData().getString(KEY_STRING);
                mHandlerTvShowInfo.setText(infoStr);
            }
        }
    };

而對于復雜的數(shù)據(jù)類型躺坟,如一個對象的傳遞就要相對復雜一些,在 Bundle 中提供了兩個方法乳蓄,專門用來傳遞對象的咪橙,但是這兩個方法也有相應的限制,需要實現(xiàn)特定的接口虚倒,當然美侦,一些 Android 自帶的類,其實已經(jīng)實現(xiàn)了這兩個接口中的某一個魂奥,可以直接使用

  • putParcelable(String key, Parcelable value):需要傳遞的對象類實現(xiàn)Parcelable接口
  • putSerializable(String key, Serializable value):需要傳遞的對象類實現(xiàn)Serializable接口

還有另外一種方式在 Message 中傳遞對象咖为,那就是使用 Message 自帶的 obj 屬性,它是一個
Object 類型歌懒,所以可以傳遞任意類型的對象茶袒,Message 自帶的還有如下幾個屬性

屬性 作用
int arg1 參數(shù)一,用于傳遞不復雜的數(shù)據(jù)哈蝇,復雜數(shù)據(jù)用 setData() 傳遞
int arg2 參數(shù)二棺妓,用于傳遞不復雜的數(shù)據(jù),復雜數(shù)據(jù)用 setData() 傳遞
Object obj 傳遞一個任意的對象
Messaenger replyTo 是作為線程通信的時候使用
int what 定義的消息碼炮赦,一般用于設定消息的標志怜跑,辨別究竟是從哪里中發(fā)來的消息

參考:
Android 中 Handler 的使用
Android -- 多線程之 Handler

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吠勘,隨后出現(xiàn)的幾起案子性芬,更是在濱河造成了極大的恐慌,老刑警劉巖看幼,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件批旺,死亡現(xiàn)場離奇詭異,居然都是意外死亡诵姜,警方通過查閱死者的電腦和手機汽煮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來棚唆,“玉大人暇赤,你說我怎么就攤上這事∠瑁” “怎么了鞋囊?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瞎惫。 經(jīng)常有香客問我溜腐,道長译株,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任挺益,我火速辦了婚禮歉糜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘望众。我一直安慰自己匪补,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布烂翰。 她就那樣靜靜地躺著夯缺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪甘耿。 梳的紋絲不亂的頭發(fā)上踊兜,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音棵里,去河邊找鬼润文。 笑死,一個胖子當著我的面吹牛殿怜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播曙砂,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼头谜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鸠澈?” 一聲冷哼從身側(cè)響起柱告,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎笑陈,沒想到半個月后际度,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡涵妥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年乖菱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓬网。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡窒所,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帆锋,到底是詐尸還是另有隱情吵取,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布锯厢,位于F島的核電站皮官,受9級特大地震影響脯倒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捺氢,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一盔憨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧讯沈,春花似錦郁岩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挤茄,卻和暖如春如叼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背穷劈。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工笼恰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歇终。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓社证,卻偏偏與公主長得像,于是被迫代替她去往敵國和親评凝。 傳聞我的和親對象是個殘疾皇子追葡,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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