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等,这些方法可以用于实现界面的定时刷新等功能,感兴趣的伙伴可以自行了解~

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: handlersendpost区别在于: 1. send方法是将消息立即发送到消息队列,而post方法是将消息延迟发送到消息队列。 2. send方法是同步的,即在发送消息后会等待消息处理完成后再继续执行后续代码,而post方法是异步的,即在发送消息后会立即返回,不会等待消息处理完成。 3. send方法可以返回一个布尔值,表示消息是否成功发送到消息队列,而post方法没有返回值。 4. send方法可以在子线程调用,但是post方法只能在主线程调用。 总之,send方法适用于需要立即处理的消息,而post方法适用于需要延迟处理的消息。 ### 回答2: handlerAndroid处理消息的机制,主要通过Message和Runnable两种方式来发送和处理消息。发送消息的方式有两种:sendpost。两者的区别在于发送消息的时机和方式不同。 send是在当前线程内同步发送消息,会等待消息处理完成后再返回。如果当前线程是UI线程,调用send发送消息会导致UI线程阻塞,容易引起ANR错误。因此,通常不建议在UI线程使用send方法发送消息。而且send方法也容易导致死锁。 post是在消息队列尾部添加一条消息,然后立即返回。也就是说,消息发送是在异步线程进行的,并不会阻塞当前线程。与send不同,post方法的处理时间无法确定,会等当前线程空闲时才处理该消息。因此,post方法是常用的一种发送消息的方式。 综上所述,在Android开发,建议使用post方法handler发送消息,特别是在UI线程。如果必须在UI线程发送消息,可以借助AsyncTask,它把任务相关的操作都放在一个独立的线程进行,避免了UI线程阻塞和ANR错误。但是,AsyncTask也有一些缺点,比如无法控制线程池的大小,如果任务过多,容易导致内存泄露。因此,在使用AsyncTask时需要特别小心。 ### 回答3: handlerandroid常用的用于实现线程间通信的类,其sendpost方法都可以用于向handler所在的线程发送消息或任务,但是二者的具体区别还是有一些的。 首先,二者的语法不同,send方法的语法为`sendMessage(Message msg)`,而post方法的语法为`post(Runnable r)`。 其次,二者在实现机制上有所不同。send方法是将消息封装成Message对象后,通过handler所在的线程的消息队列进行传输和处理;而post方法则是通过Handler所在的线程的消息队列将Runnable对象插入到队列。因此,send方法的处理过程是与MessageQueue相关的,而post方法的处理过程是与looper相关的。 最后,二者的使用场景也有所不同。由于send方法需要将消息封装成Message对象,因此在使用时需要额外编写一些代码,同时send方法的返回值是boolean类型,表示消息是否成功加入发送队列。相对而言,post方法则更加简单,只需要传入一个Runnable对象就可以了。因此,如果只是简单的向Handler所在的线程发送任务,建议使用post方法;而如果需要在任务之间传递一些数据,或者需要对消息进行一些操作,比如取消或延迟执行等,则使用send方法更加方便。 总之,对于handler来说,sendpost方法都是不可或缺的方法,二者都能够实现线程间的通信,同时也具有不同的特点和使用场景,需要根据具体情况而定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

保温杯拖把风扇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值