Android異步通信:這是一份Handler消息傳遞機制的使用教程

前言

Android開發的多線程應用場景中,Handler機制十分常用。今天,我將獻上一份 Handler機制的使用教程 ,希望你們會喜歡

Anroid異步通信Handler系列文章
Android異步通信:Handler機制學習攻略
Android異步通信:Handler使用教程
Android異步通信:Handler工作原理
Android異步通信:Handler源碼分析
Android異步通信:詳解Handler內存泄露的原因


目錄

示意圖

1. Handler 機制簡介

  • 定義
    一套 Android 消息傳遞機制 / 異步通信機制

  • 作用

在多線程的應用場景中,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現 工作線程對UI的更新處理,最終實現異步消息的處理

示意圖

  • 為什么要用 Handler消息傳遞機制
    答:多個線程并發更新UI的同時 保證線程安全。具體描述如下
示意圖
  • 總結
    使用Handler的原因:將工作線程需操作UI的消息 傳遞 到主線程,使得主線程可根據工作線程的需求 更新UI從而避免線程操作不安全的問題

2. 相關概念

關于 Handler 機制中的相關概念如下:

在下面的講解中,我將直接使用英文名講解,即 HandlerMessageMessage QueueLooper,希望大家先熟悉相關概念

示意圖

3. 使用方式

  • Handler使用方式 因發送消息到消息隊列的方式不同而不同
  • 共分為2種:使用Handler.sendMessage()、使用Handler.post()

4. 使用步驟

方式1:使用 Handler.sendMessage()

在該使用方式中,又分為2種:新建Handler子類(內部類)、匿名 Handler子類

但本質相同,即 繼承了Handler類 & 創建了子類

/** 
  * 方式1:新建Handler子類(內部類)
  */

    // 步驟1:自定義Handler子類(繼承Handler類) & 復寫handleMessage()方法
    class mHandler extends Handler {

        // 通過復寫handlerMessage() 從而確定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
         ...// 需執行的UI操作
            
        }
    }

    // 步驟2:在主線程中創建Handler實例
        private Handler mhandler = new mHandler();

    // 步驟3:創建所需的消息對象
        Message msg = Message.obtain(); // 實例化消息對象
        msg.what = 1; // 消息標識
        msg.obj = "AA"; // 消息內容存放

    // 步驟4:在工作線程中 通過Handler發送消息到消息隊列中
    // 可通過sendMessage() / post()
    // 多線程可采用AsyncTask、繼承Thread類、實現Runnable
        mHandler.sendMessage(msg);

    // 步驟5:開啟工作線程(同時啟動了Handler)
    // 多線程可采用AsyncTask、繼承Thread類、實現Runnable


/** 
  * 方式2:匿名內部類
  */
   // 步驟1:在主線程中 通過匿名內部類 創建Handler類對象
            private Handler mhandler = new  Handler(){
                // 通過復寫handlerMessage()從而確定更新UI的操作
                @Override
                public void handleMessage(Message msg) {
                        ...// 需執行的UI操作
                    }
            };

  // 步驟2:創建消息對象
    Message msg = Message.obtain(); // 實例化消息對象
  msg.what = 1; // 消息標識
  msg.obj = "AA"; // 消息內容存放
  
  // 步驟3:在工作線程中 通過Handler發送消息到消息隊列中
  // 多線程可采用AsyncTask、繼承Thread類、實現Runnable
   mHandler.sendMessage(msg);

  // 步驟4:開啟工作線程(同時啟動了Handler)
  // 多線程可采用AsyncTask、繼承Thread類、實現Runnable

方式2:使用Handler.post()

// 步驟1:在主線程中創建Handler實例
    private Handler mhandler = new mHandler();

    // 步驟2:在工作線程中 發送消息到消息隊列中 & 指定操作UI內容
    // 需傳入1個Runnable對象
    mHandler.post(new Runnable() {
            @Override
            public void run() {
                ... // 需執行的UI操作 
            }

    });

    // 步驟3:開啟工作線程(同時啟動了Handler)
    // 多線程可采用AsyncTask、繼承Thread類、實現Runnable

5. 實例講解

本文將用實例逐個講解 Handler的用法

注:

  1. 由于Handler的作用 = 將工作線程需操作UI的消息 傳遞 到主線程,使得主線程可根據工作線程的需求 更新UI,從而避免線程操作不安全的問題
  2. 故下文的實例 = 1個簡單 “更新UI操作” 的案例
  3. 主布局文件相同 = 1個用于展示的TextView,具體如下:

布局代碼:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context="com.example.carson_ho.handler_learning.MainActivity">

    <TextView
        android:id="@+id/show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="" />
</RelativeLayout>

實例的源碼地址:Carson_Ho的Github:Handler
(建議:先fork下來再看,效果會更好哦!)

5.1 使用 Handler.sendMessage()

方式1:新建Handler子類(內部類)
  • 具體使用
public class MainActivity extends AppCompatActivity {
    
    public TextView mTextView;
    public Handler mHandler;

    // 步驟1:(自定義)新創建Handler子類(繼承Handler類) & 復寫handleMessage()方法
    class Mhandler extends Handler {

        // 通過復寫handlerMessage() 從而確定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            // 根據不同線程發送過來的消息,執行不同的UI操作
            // 根據 Message對象的what屬性 標識不同的消息
            switch (msg.what) {
                case 1:
                    mTextView.setText("執行了線程1的UI操作");
                    break;
                case 2:
                    mTextView.setText("執行了線程2的UI操作");
                    break;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.show);

        // 步驟2:在主線程中創建Handler實例
        mHandler = new Mhandler();
       
        // 采用繼承Thread類實現多線程演示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                 // 步驟3:創建所需的消息對象
                 Message msg = Message.obtain();
                 msg.what = 1; // 消息標識
                 msg.obj = "A"; // 消息內存存放

                 // 步驟4:在工作線程中 通過Handler發送消息到消息隊列中
                 mHandler.sendMessage(msg);
            }
        }.start();
        // 步驟5:開啟工作線程(同時啟動了Handler)

        // 此處用2個工作線程展示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 通過sendMessage()發送
                 // a. 定義要發送的消息
                 Message msg = Message.obtain();
                 msg.what = 2; //消息的標識
                 msg.obj = "B"; // 消息的存放
                 // b. 通過Handler發送消息到其綁定的消息隊列
                 mHandler.sendMessage(msg);
            }
        }.start();

    }
}
  • 運行結果
示意圖
方式2:匿名內部類
  • 具體使用
public class MainActivity extends AppCompatActivity {
    
    public TextView mTextView;
    public Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.show);

        // 步驟1:在主線程中 通過匿名內部類 創建Handler類對象
        mHandler = new Handler(){
            // 通過復寫handlerMessage()從而確定更新UI的操作
            @Override
            public void handleMessage(Message msg) {
                // 根據不同線程發送過來的消息,執行不同的UI操作
                switch (msg.what) {
                    case 1:
                        mTextView.setText("執行了線程1的UI操作");
                        break;
                    case 2:
                        mTextView.setText("執行了線程2的UI操作");
                        break;
                }
            }
        };
        // 采用繼承Thread類實現多線程演示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                 // 步驟3:創建所需的消息對象
                 Message msg = Message.obtain();
                 msg.what = 1; // 消息標識
                 msg.obj = "A"; // 消息內存存放

                 // 步驟4:在工作線程中 通過Handler發送消息到消息隊列中
                 mHandler.sendMessage(msg);
            }
        }.start();
        // 步驟5:開啟工作線程(同時啟動了Handler)

        // 此處用2個工作線程展示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 通過sendMessage()發送
                 // a. 定義要發送的消息
                 Message msg = Message.obtain();
                 msg.what = 2; //消息的標識
                 msg.obj = "B"; // 消息的存放
                 // b. 通過Handler發送消息到其綁定的消息隊列
                 mHandler.sendMessage(msg);
            }
        }.start();

    }

}
  • 運行結果
示意圖

5.2 使用 Handler.post()

  • 具體使用
public class MainActivity extends AppCompatActivity {
    
    public TextView mTextView;
    public Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.show);

        // 步驟1:在主線程中創建Handler實例
        mHandler = new Handler();

        // 步驟2:在工作線程中 發送消息到消息隊列中 & 指定操作UI內容
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 通過psot()發送,需傳入1個Runnable對象
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        // 指定操作UI內容
                        mTextView.setText("執行了線程1的UI操作");
                    }

                });
            }
        }.start();
        // 步驟3:開啟工作線程(同時啟動了Handler)

        // 此處用2個工作線程展示
        new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(6000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mTextView.setText("執行了線程2的UI操作");
                    }

                });
            }
        }.start();

    }

}
  • 運行結果


    示意圖

至此,關于Handler的異步消息傳遞機制的使用講解完畢。


6. 總結

  • 本文對Handler異步通信傳遞機制的使用進行了全面講解
  • 下一篇文章我將對講解Android Handler的相關知識,感興趣的同學可以繼續關注Carson_Ho的簡書

Anroid異步通信Handler系列文章
Android異步通信:Handler機制學習攻略
Android異步通信:Handler使用教程
Android異步通信:Handler工作原理
Android異步通信:Handler源碼分析
Android異步通信:詳解Handler內存泄露的原因


歡迎關注Carson_Ho的簡書

不定期分享關于安卓開發的干貨,追求短、平、快,但卻不缺深度


請點贊!因為你的鼓勵是我寫作的最大動力!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容