Android Handler中post方法与send方法的区别及使用

概述

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) {
    
    
        // 使用send方法更新UI的方式:
        // 重写handleMessage方法,在该方法内更新UI
        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();
    // 模拟send方法更新UI的操作
    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();
    // 模拟post方法更新UI的操作
    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){
    
    
  //如果是post,callback不为空,直接进入handleCallback
  if(msg.callback != null){
    
    
    handleCallback(msg);
    }else{
    
    
      //如果是sendMessage,且创建handler时没有传入callback,则callback为空,直接进入handleMessage,也就是我们自己复写的处理Message的方法
      if(mCallback !=null){
    
    
        if(mCallback.handleMessage(msg)){
    
    
          return;
        }
      }
    handleMessage(msg);
    }
}
//直接run并不会启动新线程,所以这就是post的runnable里面可以直接更新UI的原因
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) {
    
    
            // 使用send方法更新UI的方式:
            // 重写handleMessage方法,在该方法内更新UI
            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();
        // 模拟send方法更新UI的操作
        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();
            }
        });
        // 模拟post方法更新UI的操作
        mBtnPost.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                handlerPost.post(new Runnable() {
    
    
                    @Override
                    public void run() {
    
    
                        mTvTxt.setText("使用post方法更新UI");
                    }
                });
            }
        });
    }

    /**
     * 绑定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一类方法:
send
(3)使用post一类方法:
post

后记

(1)参考博文:https://www.jianshu.com/p/2c5c4e5558f1
(2)上述代码只是为了展示如何使用Handler的Demo,没有考虑内存泄漏等情况;如send按钮中,理论上每次点击该Button都会新建一个线程,可以考虑使用线程池等实现线程复用;
(3)send一类方法与post一类方法都有提供延时发送消息的封装方法,如sendMessageDelayed、postDelayed等,这些方法可以用于实现界面的定时刷新等功能,感兴趣的伙伴可以自行了解~

猜你喜欢

转载自blog.csdn.net/weixin_46269688/article/details/124269048
今日推荐