Handler源码分析

本文详细分析了Android中Handler的基本使用、源码以及它与Looper、MessageQueue之间的关系。在创建Handler前需要调用Looper.prepare(),主线程默认已准备Looper。Handler构造时关联了当前线程的Looper和MessageQueue。消息发送通过sendMessage()方法,最终由Looper.loop()调度,通过dispatchMessage()回调handleMessage(),实现异步消息处理。同时,文章还探讨了post()方法与runOnUiThread()的工作原理。
摘要由CSDN通过智能技术生成

Handler源码分析

Android异步消息处理机制完全解析,带你从源码的角度彻底理解(郭霖)

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系(鸿洋)

一、Handler基本使用

Handler是Android中最常用的了,主要作用无非就是用来解决子线程中无法更新UI的问题,一般在子线程中获取到的数据,可以通过Handler发送到主线程中然后进行UI操作,所以在分析Hanlder的时候,还是有必要先看一下Handler的基本使用步骤。代码如下:

public class TestActivity extends Activity {
   

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    private Handler threadHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        new Thread(new Runnable() {
            @Override
            public void run() {
                threadHandler = new Handler();
                mHandler.sendMessage(new Message());
            }
        }).start();
    }
}

上面代码中在主线程和子线程中分别创建了一个Hanlder,看上去这段代码是没什么问题,但其实运行的时候会报错,java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-4,5,main] that has not called Looper.prepare()
,这里表示无法在子线程中创建Handler,因为子线程中在创建Handler的时候没有调用Looper.prepare(),那么接下来我们在子线程中加上Looper.prepare()试试,如下:

new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                threadHandler = new Handler();
                mHandler.sendMessage(new Message());
            }
        }).start();

这时程序就能正常运行了。这里需要知道,一个线程中如果要创建Handler,那么在实例化Hanler之前需要调用Looper.prepare()。那么这里大家可能会有一个疑问,那就是为什么主线程中不需要调用Looper.prepare()呢?

这是因为我们应用在启动的时候会执行ActivityThread中的main()方法,而main()方法中调用了Looper.prepareMainLooper();,点击进去继续查看源码可以发现Looper.prepareMainLooper()方法调用的就是prepare()方法,这里即表明主线程在初始化的时候就调用了Looper.prepare()方法。知道了这些,我们接下来可以分析来分析Handler的源码了。其实一说到分析Handler源码,那必然是离不开Message,Looper,MessageQueue这几个类的源码的。

二、源码分析(Handler、Looper、MessageQueue之间的关系)

通过上面的一个流程我们知道在创建Handler之前需要先调用Looper.prepare()方法,那么我们首先来看看Looper.prepare()这个方法的源码到底是什么?

 public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper的prepare方法调用了一个重载方法,那么接下来我们就该看看sThreadLocal是什么东西了。
Android的消息机制之ThreadLocal的工作原理

  static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

sThreadLocal的set于get方法和map的set,get方法类似,这里然后分析

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

,首先判断sThreadLocal.get()获取到的Looper是否为空,不为空则抛出异常,否则创建一个Looper保存,那么从这里我们可以看出来在一个线程中Looper.prepare()方法只能够掉一次,如果调用了一次以上则会抛出异常。
好了,Looper.prepare()方法就说到这,接着往下看,在执行完,Looper.prepare()方法后,我们可以创建一个Handler,那这里我们看一下Handler的构造函数源码

public Handler(Callback callback, boolean async) {
   mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
 }

上面只列出了主要代码,我们一行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值