runOnUiThread是如何解决子线程不能更新主线程View的问题的?

上篇文章:子线程不显示Toast? 分析了子线程不显示Toast的原因,并通过Looper.prepare(); Looper.loop();解决。这篇文章我们通过runOnUiThread()解决,并分析原因。

本文:Android 12 api=32

public class MainActivity extends AppCompatActivity {

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

        new Thread(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this,"子线程",Toast.LENGTH_SHORT).show();
                    }
                });

            }
        }).start();

    }
}

runOnUiThread()方法是Activity.java中的成员方法,被final修饰,不能被重写。此方法内部,通过mHandler.post()把Runnable发送出去了。这个mHandler 是Activity.java的成员变量,但是被@UnsupportedAppUsage 注解修饰,所以子类不能直接使用,需要自己实例化新的Handler对象。

Activity.java

    // we must have a handler before the FragmentController is constructed
    @UnsupportedAppUsage
    final Handler mHandler = new Handler();
    ...	
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

这个@UnsupportedAppUsage 注解是从Android 11®版本引入的,具体参考:@UnsupportedAppUsage注解。Android 6.0里面没有这个注解,源码如下。不过,看注释// we must have a handler before the FragmentController is constructed,保险起见还是自己新实例化一个Handler对象。
Android 6.0 Activity.java

    // we must have a handler before the FragmentController is constructed
    final Handler mHandler = new Handler();

不扯远了。继续看Handler的post的方法。

	//Handler.java
    public final boolean post(@NonNull Runnable r) {
    	//这里通过getPostMessage() 把Runnable转为了一个Message对象
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        //Runnable 保存在Message的成员变量callback里面。
        m.callback = r;
        return m;
    }
	//Message.java
	public final class Message implements Parcelable {
		...
	    @UnsupportedAppUsage
	    /*package*/ Runnable callback;
	    ...
	}

总接一下:runOnUiThread()方法,是Activity的方法。它的入参Runnable最终被保存在了一个Message对象的callback变量里面,然后就和sendMessage()方法的流程一样了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android 中,线程线程之间可以通过以下方式进行通信: 1. Handler:Handler 是 Android 中一种常用的线程间通信机制。线程可以创建 Handler 对象,并将其传递给线程线程就可以通过 Handler 发送消息到线程线程收到消息后,可以通过 Handler 处理消息。 2. AsyncTask:AsyncTask 是 Android 中一个方便的异步任务框架,它可以在线程中执行耗时操作,然后将执行结果传递给线程。AsyncTask 可以通过重写其 onPostExecute() 方法,在线程中处理执行结果。 3. runOnUiThread() 方法:runOnUiThread() 方法是 Activity 类提供的一个方法,它可以让线程中的代码在线程中执行。线程可以通过 runOnUiThread() 方法将更新 UI 的任务发送到线程。 4. View.post() 方法:View.post() 方法是 View 类提供的一个方法,它可以让线程中的代码在线程中执行。线程可以通过 View.post() 方法将更新 UI 的任务发送到线程。 5. Broadcast Receiver:Broadcast Receiver 是 Android 中一种广播机制,它可以让应用程序中的不同组件之间进行通信。线程可以通过发送广播的方式将数据传递给线程。 6. Messenger:Messenger 是 Android 中一种轻量级的 IPC 机制,它可以让不同进程之间进行通信。线程可以创建 Messenger 对象,并将其传递给线程线程就可以通过 Messenger 发送消息到线程线程收到消息后,可以通过 Messenger 处理消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zhangjin1120

可靠的文章费时费力,希望支持

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

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

打赏作者

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

抵扣说明:

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

余额充值