Android 談?wù)?Handler 那些事

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

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

  • Handler 是什么
  • Handler 的兩個(gè)體系
  • Message

一、Handler是什么

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

Handler 可以用來在多線程之間進(jìn)行通信,在另一個(gè)線程中去更新 UI 線程中的 UI 控件只是 Handler 使用中的一種典型案例,除此之外,Handler 還可以做其他很多的事情,Handler 是 Thread 的代言人,是多線程之間通信的橋梁,通過 Handler,我們可以在一個(gè)線程中控制另一個(gè)線程去做某些事

二、Handler的兩個(gè)體系

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

  • Post:Post允許把一個(gè) Runnable 對(duì)象入隊(duì)到消息隊(duì)列中,它的方法有:post(Runnable)、PostAtTime(Runnable, long)、postDelayed(Runnable, long)
  • sendMessage:sendMessage允許把一個(gè)包含消息數(shù)據(jù)的Message對(duì)象壓入到消息隊(duì)列中,它的方法有sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message, long)、sendMessageDelayed(Message, long)

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

1、Post

對(duì)于 Handler 的 Post 方式來說,它會(huì)傳遞一個(gè) Runnable 對(duì)象到消息隊(duì)列中,在這個(gè) Runnable 對(duì)象中,重寫 run() 方法,一般是在這個(gè) run() 方法中寫入需要在UI線程中的操作

在 Handler 中,關(guān)于 Post 方式的方法有

方法名稱 作用
boolean post(Runnable r) 把一個(gè) Runnabled 入隊(duì)到消息隊(duì)列中,UI 線程從消息隊(duì)列中取出這個(gè)對(duì)象后,立即執(zhí)行
boolean postAtTime(Runnable r, long uptimeMills) 把一個(gè) Runnable 入隊(duì)到消息隊(duì)列中,UI線程從消息獨(dú)立列中取出這個(gè)對(duì)象后,在特定的時(shí)間執(zhí)行
boolean postDelayed(Runnable r, long delayMills) 把一個(gè) Runnable 入隊(duì)到消息隊(duì)列中,UI線程從消息隊(duì)列中能夠取出這個(gè)對(duì)象后,延遲delayMills秒執(zhí)行
void removeCallbacks(Runnable r) 從消息隊(duì)列中移除一個(gè) Runnable 對(duì)象

示例代碼

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

有一點(diǎn)需要注意的是,對(duì)于 Post 方式而言,它其中的 Runnable 對(duì)象的 run() 方法的代碼,均執(zhí)行在UI線程上,所以如果是不能在 UI 線程上執(zhí)行的操作,如網(wǎng)絡(luò)請(qǐng)求之類的,一樣無法使用Post方式執(zhí)行

2、sendMessage

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

方法 作用
Message obtainMessage() 獲取一個(gè)Message對(duì)象
boolean sendMessage() 發(fā)送一個(gè)Message對(duì)象到消息隊(duì)列中,并在UI線程取到消息之后,立即執(zhí)行
boolean sendMessageDelayed() 發(fā)送一個(gè)Message對(duì)象到消息隊(duì)列中,在 UI 線程取到消息后,延遲執(zhí)行
boolean sendEmptyMessage(int what) 發(fā)送一個(gè)空Message對(duì)象到消息隊(duì)列中,并在 UI 線程取到消息之后,立即執(zhí)行
boolean sendEmptyMessageDelayed(int what) 發(fā)送一個(gè)空Message對(duì)象到消息隊(duì)列中,并在 UI 線程取到消息之后,延遲執(zhí)行
void removeMessage() 從消息隊(duì)列中移除一個(gè)未響應(yīng)的消息

示例代碼

        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 的方式把消息入隊(duì)到消息隊(duì)列中,需要傳遞一個(gè) Message 對(duì)象,而在 Handler,需要重寫 handleMessage() 方法,用于獲取工作線程中傳遞過來的消息,此方法運(yùn)行在 UI 線程上

1、獲取一個(gè) Message 對(duì)象

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

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

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

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

示例代碼

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);
            }
        }
    };

而對(duì)于復(fù)雜的數(shù)據(jù)類型,如一個(gè)對(duì)象的傳遞就要相對(duì)復(fù)雜一些,在 Bundle 中提供了兩個(gè)方法,專門用來傳遞對(duì)象的,但是這兩個(gè)方法也有相應(yīng)的限制,需要實(shí)現(xiàn)特定的接口,當(dāng)然,一些 Android 自帶的類,其實(shí)已經(jīng)實(shí)現(xiàn)了這兩個(gè)接口中的某一個(gè),可以直接使用

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

還有另外一種方式在 Message 中傳遞對(duì)象,那就是使用 Message 自帶的 obj 屬性,它是一個(gè)
Object 類型,所以可以傳遞任意類型的對(duì)象,Message 自帶的還有如下幾個(gè)屬性

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

參考:
Android 中 Handler 的使用
Android -- 多線程之 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)容