Android Handler消息机制详解

前言

在Android中,只有主线程才能更新UI,但是主线程不能进行耗时操作,否则会产生ANR异常,所以常常把耗时操作放到其他子线程进行。如果在子线程中需要更新UI,一般都是通过Handler发送消息,主线接收消息后进行相应的UI逻辑处理。

一.什么是Handler

Handler是一个消息分发对象。

Handler是Android系统提供的一套用来更新UI的机制,也是一套消息处理机制,可以通过Handler发消息,也可以通过Handler处理消息。

二.为什么使用Handler

为了解决多线程并发的问题!

比如:如果在一个activity中有多个线程同时更新UI,并且没有加锁,就会出现界面错乱的问题。但是如果对这些更新UI的操作都加锁处理,又会导致性能下降。出于对性能问题的考虑,Android提供这一套使用Handler更新UI的机制,不用再去关心多线程的问题,所有的更新UI的操作,都是在主线程的消息队列中去轮询处理的。

在Android系统中,只有主线程才能更新UI,提到主线程,就不得说一下ActivityThread,一个应用内部的逻辑处理都是在ActivityThread内部依靠Handler来进行处理的,比如:activity、service相关的创建等相关逻辑,在应用创建后,会调用到ActivityThread内部的main()方法,逻辑如下:

public static void main(String[] args) {
    ......
    //创建Looper
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    //创建Handler
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    //开启loop()循环
    Looper.loop();
} 

从上面可以看到在ActivityThread里面的main()中,执行了Looper.prepareMainLooper()及Looper.loop(),接下来一起分析一下Android系统的消息处理机制。

三.源码分析

Android内部的消息处理机制主要是由Handler、Looper、MessageQueue、Message来组成的,具体分工如下:

  • Handler:负责发送消息及处理消息
  • Looper:不断的从消息队列中取出消息,并且将消息给发送本条消息的Handle
  • MessageQueue:负责存储消息
  • Message:消息本身,负责携带数据

1.Looper

Looper分为主线程和其他子线程,前面讲到,主线程的Looper是在进程启动后调用ActivityThread的main()里面通过prepareMainLooper()创建的:

a.prepareMainLooper()
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
} 

prepareMainLooper()内部会调用prepare(false)来进行创建,且Looper是不能退出的,然后对sMainLooper进行赋值;

b.prepare()
//只能通过Looper.prepare()方法去初始化一个Looper
public static void prepare() {
    prepare(true);
}

//一个线程中只能有一个Looper对象,否则在第二次尝试初始化Looper的时候,就会抛出异常
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));//创建了new Looper
} 

子线程通过prepare()内部调用prepare(true)来创建对应的Looper,且Looper是可以退出的,为什么要退出,后面会讲到;

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

private Looper(boolean quitAllowed) {
    //创建Looper的时候会创建一个MessageQueue
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
} 

Looper构造方法内会创建MessageQueue(),为后续消息处理做准备,然后获取到当前的Thread赋值给mThread,后续通过getThread()可以获取到当前的thread,可以用来判断是否为主线程。

最后

如果大伙有什么好的学习方法或建议欢迎大家在评论中积极留言哈,希望大家能够共同学习、共同努力、共同进步。

小编在这里祝小伙伴们在未来的日子里都可以 升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰!!

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,需要一份小编整理出来的学习资料的关注我主页或者点击扫描下方二维码免费领取~

这里是关于
我自己的Android 学习,面试文档,视频收集大整理**,有兴趣的伙伴们可以看看~

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值