前言
在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
機制中的相關概念如下:
在下面的講解中,我將直接使用英文名講解,即
Handler
、Message
、Message Queue
、Looper
,希望大家先熟悉相關概念
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
的用法
注:
- 由于
Handler
的作用 = 將工作線程需操作UI的消息 傳遞 到主線程,使得主線程可根據工作線程的需求 更新UI,從而避免線程操作不安全的問題- 故下文的實例 = 1個簡單 “更新
UI
操作” 的案例- 主布局文件相同 = 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的簡書
不定期分享關于安卓開發的干貨,追求短、平、快,但卻不缺深度。