概述
Handler机制是Android中线程通信的一种常用方式,应用场景如子线程通知主线程进行UI更新等。使用handler发送消息有post和sendMessage两类方法,本文主要记录这两种方法的使用以及区别。
Handler使用sendMessage方法
sendMessage()方法传入的参数是Message对象,在工作线程传入Message对象后,在主线程重写Handler的handleMessage方法,以此实现更新UI等功能,如以下代码:
private Handler handlerSend = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
mTvTxt.setText("使用send方法更新UI");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initBind();
mBtnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
handlerSend.sendEmptyMessage(1);
}
});
thread.start();
}
});
}
Handler使用post方法
post()方法传入的参数是一个Runnable对象。可以在工作线程重写该Runnable对象的run方法,并将更新UI等操作放在run方法内,具体代码如下:
private Handler handlerPost = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initBind();
mBtnPost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handlerPost.post(new Runnable() {
@Override
public void run() {
mTvTxt.setText("使用post方法更新UI");
}
});
}
});
}
注意:Handler对应的Looper在哪个线程,此处Runnable对象的run方法就在哪个线程执行。例如上述代码Handler对应的Looper位于主线程,因此run方法将在主线程中执行,因此可以在run方法中进行UI更新操作。
post方法与send方法的区别
在handler从MessageQueue中取出Message的过程中,可以看到不同的回调过程,源码如下:
public void dispatchMessage(Message msg){
if(msg.callback != null){
handleCallback(msg);
}else{
if(mCallback !=null){
if(mCallback.handleMessage(msg)){
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message msg){
msg.callback.run();
}
(1)post一类的方法发送的是Runnable对象,但是最后还是会被封装成Message对象,将Runnable对象赋值给Message对象中的callback字段,然后交由sendMessageAtTime()方法发送出去。 在处理消息时,会在dispatchMessage()方法里首先被handleCallback(msg)方法执行,实际上就是执行Message对象里面的Runnable对象的run方法。
(2)sendMessage一类方法发送的消息直接是Message对象,处理消息时,在dispatchMessage里优先级会低于handleCallback(msg)方法,是通过自己重写的handleMessage(msg)方法执行。
(3)可以看出,post方法与send方法本质上并没有什么区别,更多的是使用方法上存在着一些差异。
全部代码
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"
android:textAllCaps="false"
android:id="@+id/btn_send"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Post"
android:textAllCaps="false"
android:id="@+id/btn_post"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="初始化状态"
android:textSize="24sp"
android:textColor="@color/black"
android:id="@+id/tv_txt"
/>
</LinearLayout>
MainActivity:
package com.example.handlerdemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button mBtnSend, mBtnPost;
private TextView mTvTxt;
private Handler handlerSend = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
mTvTxt.setText("使用send方法更新UI");
}
}
};
private Handler handlerPost = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initBind();
mBtnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
handlerSend.sendEmptyMessage(1);
}
});
thread.start();
}
});
mBtnPost.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handlerPost.post(new Runnable() {
@Override
public void run() {
mTvTxt.setText("使用post方法更新UI");
}
});
}
});
}
private void initBind() {
mBtnSend = findViewById(R.id.btn_send);
mBtnPost = findViewById(R.id.btn_post);
mTvTxt = findViewById(R.id.tv_txt);
}
}
效果图
(1)初始界面: (2)使用send一类方法: (3)使用post一类方法:
后记
(1)参考博文:https://www.jianshu.com/p/2c5c4e5558f1 (2)上述代码只是为了展示如何使用Handler的Demo,没有考虑内存泄漏等情况;如send按钮中,理论上每次点击该Button都会新建一个线程,可以考虑使用线程池等实现线程复用; (3)send一类方法与post一类方法都有提供延时发送消息的封装方法,如sendMessageDelayed、postDelayed等,这些方法可以用于实现界面的定时刷新等功能,感兴趣的伙伴可以自行了解~
|