欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android Handler 消息机制

程序员文章站 2022-07-14 19:27:46
...

一、用于线程间通讯 (进程可以包含一到多个线程,进程和线程的本质区别是能否共享资源)

二、子线程UI操作 都是通过Handler实现 (UI线程不是线程安全的,不能在子线程进行处理)

 

1. Handler的post()方法

 

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

2. View的post()方法

当View没有被attach到window的时候,最后runnable的处理不是通过MessageQueue,而是ViewRootImpl自己在下一个performTraversals到来的时候执行,也就是说会延时执行,

 

getRunQueue().executeActions(mAttachInfo.mHandler);
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }

    // Postpone the runnable until we know on which thread it needs to run.
    // Assume that the runnable will be successfully placed after attach.
    getRunQueue().post(action);
    return true;
}

3. Activity的runOnUiThread()方法

@Override
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

 

三、消息机制

 

  • Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;(what / arg1 / arg2 / obj)
  • MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);读取会自动删除消息,单链表维护,在插入和删除上有优势。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
  • Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
  • Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。

 

Looper.prepare() 每个线程只能执行一次, 会创建Looper对象,Looper对象实例化时会创建MessageQueue

prepare(true),表示的是这个Looper运行退出,而对于false的情况则表示当前Looper运行时不允许退出。

如果是在子线程里实例化一个Handler,需要主动调用Looper.prepare()

ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。TLS常用的操作方法:

 

 
public static void main(String[] args) {

    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

Looper#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();
    }
}

 

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));
}
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

 

Looper#loop()

 

 

/*package*/ Handler target;
/*package*/ Runnable callback;
public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    for (;;) {
        Message msg = queue.next(); // might block
        try {
            msg.target.dispatchMessage(msg);
        } finally {
           
        }
        msg.recycleUnchecked();
    }
}

Handler#dispatchMessage() 分发消息调用callback.

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

1:message.callback.run()  msg的callback是个runnable对象

Handler#handleCallback()

private static void handleCallback(Message message) {
    message.callback.run();
}

 

2:mCallback.handleMessage  mCallback是handler实例化时传递过来的接口

Handler 实例化

public Handler(Callback callback) {
    this(callback, false);
}
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;
    mCallback = callback;
    mAsynchronous = async;
}

3:handleMessage() 子类实现handler时需要重写的方法

 

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

 

 

 

ActivityThread是App的入口,main里做了死循环的操作,为啥没有卡死呢?

https://www.zhihu.com/question/34652589

thread.attach(false);便会创建一个Binder线程(具体是指ApplicationThread,Binder的服务端,用于接收系统服务AMS发送来的事件),该Binder线程通过Handler将Message发送给主线程

 

主线程的死循环一直运行是不是特别消耗CPU资源呢? 其实不然,这里就涉及到Linux pipe/epoll机制,简单说就是在主线程的MessageQueue没有消息时,便阻塞在loop的queue.next()中的nativePollOnce()方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,通过往pipe管道写端写入数据来唤醒主线程工作。这里采用的epoll机制,是一种IO多路复用机制,可以同时监控多个描述符,当某个描述符就绪(读或写就绪),则立刻通知相应程序进行读或写操作,本质同步I/O,即读写是阻塞的。 所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源。

 

Activity的生命周期都是依靠主线程的Looper.loop,当收到不同Message时则采用相应措施:
在H.handleMessage(msg)方法中,根据接收到不同的msg,执行相应的生命周期。