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_:不断的从消息队列中取出消息,并且将消息给发送本条消息的Handler

   _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,可以用来判断是否为主线程。

更多Android可以查看我的个人介绍!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容