java中的handler理解_Handler的运行机制(个人理解)

一. Handler的主要作用

我们都知道,在android里是不能在子线程里更新UI的, 简单说一下原因: 更新UI时会调用ViewRootImpl.checkThread() 检查当前线程是否与mThread (控件初始化时所在的线程)是否一致,假如不一致,则抛出异常,ViewRootImpl.java关键代码如下:

public ViewRootImpl(Context context, Display display) {

mThread = Thread.currentThread();

}

void checkThread() {

if (mThread != Thread.currentThread()) {

throw new CalledFromWrongThreadException(

"Only the original thread that created a view hierarchy can touch its views.");

}

}

Handler的主要作用:在子线程中发送消息, 在主线程中更新UI。

二. Handler的基本使用

1. Handler.sendMessage(msg)

@SuppressLint("HandlerLeak")

private Handler mHandler = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

mTextView.setText(msg.obj + ""); //更新UI

}

};

//子线程发送消息

new Thread(new Runnable() {

@Override

public void run() {

Message message = new Message();

message.obj = "6666";

mHandler.sendMessage(message);

}).start();

2. Handler.post(msg)

@SuppressLint("HandlerLeak")

private Handler mHandler = new Handler();

//子线程发送消息

new Thread(new Runnable() {

@Override

public void run() {

mHandler.post(new Runnable() { //切换到主线程更新UI

@Override

public void run() {

mTextView.setText("123456");

}

});

}).start();

二. Handler的运行机制(API28源码解读)

1. Handler.sendMessage(msg)做了些什么?

Handler.java里面的方法(部分关键代码):

sendMessage()→sendMessageDelayed()→sendMessageAtTime()→enqueueMessage;

public final boolean sendMessage(Message msg){

return sendMessageDelayed(msg, 0);

}

public final boolean sendMessageDelayed(Message msg, long delayMillis){

if (delayMillis < 0) {

delayMillis = 0;

}

return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {

MessageQueue queue = mQueue;

return enqueueMessage(queue, msg, uptimeMillis);

}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this;

return queue.enqueueMessage(msg, uptimeMillis);

}

从上面来看,Handler最终调用了MessageQueue.enqueueMessage()

注意: msg.target = this; msg.target 表示当前对象Handler, 后面Looper.loop()用到

MessageQueue.enqueueMessage()

关键代码如下:

boolean enqueueMessage(Message msg, long when) {

msg.when = when;

Message p = mMessages;

if (p == null || when == 0 || when < p.when) {

msg.next = p;

mMessages = msg;

} else {

Message prev;

for (;;) {

prev = p;

p = p.next;

if (p == null || when < p.when) {

break;

}

}

msg.next = p;

prev.next = msg;

}

}

return true;

}

从代码中慢慢分析,我们可以得出结论:其实MessageQueue.enqueueMessage()方法就是把传进来的Message消息对象,按照时间顺序、队列的结构 保存起来。

在这里,我们并没有看到Handler.handleMessage()方法的执行,继续往下看。

2. 从ActivityThread.main()分析

我们就不慢慢从问题引进来了,直奔主题。

public static void main(String[] args) {

Looper.prepareMainLooper(); //初始化

Looper.loop();

}

2.1.首先我们看Looper.prepareMainLooper()做了些什么

prepareMainLooper()→prepare()

public static void prepareMainLooper() {

prepare(false);

synchronized (Looper.class) {

if (sMainLooper != null) { //如果进行第二次初始化,则回报异常

throw new IllegalStateException("The main Looper has already been prepared.");

}

sMainLooper = myLooper(); //赋值

}

}

//有且只有一个ThreadLocal对象

static final ThreadLocal sThreadLocal = new ThreadLocal();

private static void prepare(boolean quitAllowed) {

//进入ThreadLocal源码里set()和get()可以看出,每个线程只保存一个Looper对象

//所以每个线程只能调用一次prepare(),否则会抛异常

if (sThreadLocal.get() != null) {

throw new RuntimeException("Only one Looper may be created per thread");

}

//ThreadLocal保存Looper对象

sThreadLocal.set(new Looper(quitAllowed));

}

注意:prepare()方法 这里有2个关键点:

(1) sThreadLocal.set() 和 get()方法

(2) Looper.java构造方法new Looper().

(1). ThreadLocal.java 的set()和get()

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null) {

@SuppressWarnings("unchecked")

T result = (T)e.value;

return result;

}

}

return setInitialValue();

}

public void set(T value) {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null)

map.set(this, value);

else

createMap(t, value);

}

set():给当前线程赋值一个:Loop对象

get():获取当前线程的Loop对象

(2). Looper.java构造方法

private Looper(boolean quitAllowed) {

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

主要初始化消息队列MessageQueue,即:一个Loop有一个MessageQueue消息队列对象

总结:Looper.prepareMainLooper() 主要作用:

初始化Looper.sThreadLocal.set(new Loop()当前线程唯一对象)

初始化 MessageQueue对象, new Loop() 对应一个MessageQueue对象

2.2. Looper.loop();

下面是部分的关键代码

public static void loop() {

final Looper me = myLooper(); //获取唯一的Loop对象

if (me == null) { //假如sThreadLocal.set()没有赋值,则会抛出异常

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

final MessageQueue queue = me.mQueue; //获取队列消息对象

for (;;) {

Message msg = queue.next();

if (msg == null) {

return;

}

try {

// 从Handler.enqueueMessage() 方法里面可以看出,msg.target就是当前的Handler对象

msg.target.dispatchMessage(msg);

}

msg.recycleUnchecked(); //资源缓存和回收

}

}

public static @Nullable Looper myLooper() {

return sThreadLocal.get();

}

代码里面都有注释,最核心代码是msg.target.dispatchMessage(msg),msg.target就是当前的Handler对象,

接下来我们来看Handler.dispatchMessage().

public void dispatchMessage(Message msg) {

if (msg.callback != null) {

handleCallback(msg);

} else {

if (mCallback != null) {

if (mCallback.handleMessage(msg)) {

return;

}

}

handleMessage(msg);

}

}

这里就执行了handleMessage()方法

2.3. 资源回收处理 msg.recycleUnchecked()

private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

void recycleUnchecked() {

flags = FLAG_IN_USE;

what = 0;

arg1 = 0;

arg2 = 0;

obj = null;

replyTo = null;

sendingUid = -1;

when = 0;

target = null;

callback = null;

data = null;

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

}

}

}

结论:Msg 对象范围0到50个

最后图解,如下图:

969a4e8c1584

Handler机制原理图.png

三. Handler 常见问题

1. 在子线程中创建Handler对象会抛出异常。

原因:Looper.sThreadLocal.set()没有初始化ThreadLocalMap对象,导致Handler.mLooper = null;

public Handler(Callback callback, boolean async) {

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can't create handler inside thread " + Thread.currentThread()

+ " that has not called Looper.prepare()");

}

}

解决方法:

1.先执行Looper.prepare()初始化,一个线程只能执行一次。

创建Handler对象。

Looper.loop(); //开始循环 发送队列消息 ,如果没有这一句,是接收不到消息的。

2. handler.post() 和 sendMessage的区别。

写法不一样

post()的msg对象是去缓存里面找的,假如缓存没有就创建一个新的msg对象,

sendMessage的msg对象是从外面传进来的,可以自定义带参数。

public final boolean post(Runnable r) {

return sendMessageDelayed(getPostMessage(r), 0);

}


版权声明:本文为weixin_39942213原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。