Android Handler理解

1,758 阅读4分钟

Handler是什么

Handler是Android 线程间通信工具类。

一般用于子线程向主线程发送消息,将子线程中执行结果通知主线程,从而在主线程中执行UI更新操作。

源码角度理解  

Handler负责发送(sendMessage)和处理消息(handleMessage)
1)Message:消息载体,包含消息id(what)、消息处理对象(obj)、Runnable接口等。Handler发送一条消息后,会将该消息加入到MessageQueue统一消息处理队列中。
2)MessageQueue:消息队列。用来存放Handler发送的消息的队列,单链表实现
3)Looper:消息泵,通过Looper.loop( )创建一个死循环,不断地从MessageQueue中抽取Message,Message通过绑定的内部target(handler类型),msg.target.dispatchMessage(msg)将该消息传给对应的Handler接收。在dispatchMessage方法内调用handleCallback或handleMessage方法

ThreadLocal理解

创建Handler对象时,需要先为这个Handler创建Looper.prepara( )新建一个looper对象。一个线程中只会有一个looper。因为looper使用ThreadLocal.set方法。在set方法中,会对应着当前Thread,将Looper存储在其成员变量ThreadLocalMap中。其中key是ThreadLocal,value是looper。因此looper-threadLocal-Thread是一一对应关系。

实际上ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

对象存放在哪里

在Java中,栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

Handler发送和处理消息过程分析

Handler发送消息:Handler.sendMessage(Message message)

Handler处理信息:

 new  Handler(){
        // 通过复写handlerMessage()从而确定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
                ...// 需执行的UI操作
            }
    };

sendMessage方法将message 入队messageQueue(单链表实现)

在ActivityThread中会调用Looper.prepareMainLooper()生成looper,looper中会创建MessageQueue 。Looper.loop( )中有个死循环,不断从messageQueue中取message。

public static void main(String[] args) {
    Looper.prepareMainLooper();
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper类

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
 public static void loop() {
        
        ...// 仅贴出关键代码

        // 1. 获取当前Looper的消息队列
            final Looper me = myLooper();         
            final MessageQueue queue = me.mQueue;
            for (;;) {  
            Message msg = queue.next(); 
            if (msg == null) {
                return;
            }
            // next():取出消息队列里的消息
            // 若取出的消息为空,则线程阻塞 

            // 2.2 派发消息到对应的Handler
            msg.target.dispatchMessage(msg);
            // 把消息Message派发给消息对象msg的target属性
            // target属性实际是1个handler对象
        // 3. 释放消息占据的资源
        msg.recycle();
        }
}

Handler中的dispatchMessage方法

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

ActivityThread是什么?

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 *
 * {@hide}
 */
public final class ActivityThread extends ClientTransactionHandler {
private ContextImpl mSystemContext;
static volatile IPackageManager sPackageManager;
final ApplicationThread mAppThread = new ApplicationThread();//不是线程,只是个IBinder对象,AMS持有此对象的代理对象,从而通知ActivityThread管理其他事情
final Looper mLooper = Looper.myLooper();
final H mH = new H();//主线程Handler
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();//activity栈
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();
Configuration mConfiguration;
private static volatile ActivityThread sCurrentActivityThread;//ActivityThread单例
Instrumentation mInstrumentation;
@GuardedBy("mResourcesManager")
final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<>();
@GuardedBy("mResourcesManager")
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<>();
private final ResourcesManager mResourcesManager;
public static void main(String[] args) {

  }
}
public abstract class ClientTransactionHandler {
}

从源码可以看到,ActivityThread虽然名字里包含Thread,并不是主线程,只是运行在主线程中的对象。其调用时机为:

当ZygoteInit启动时,会分裂出system_server并进行不断地ipc轮询,system_server会创建AMS等服务。当你在桌面点击一个app图标时,并且这个app在内存中是无实例的。ams会通知system_server,由system_server通知系统进程ZygoteInit去fork出虚拟机进程(应用进程),我们知道进程的执行单位是线程,因此在虚拟机进程里会初始化一个主线程来执行,在主线程中会调用ActivityThread的main方法。main方法的调用是在子进程的主线程中。

ActivityThread是用来管理主线程执行,与AMS交互并且管理Activity和Service、BroadcastReceiver等。