您的位置:首页 > 移动开发 > Android开发

Android消息机制之Handler的深入理解

2017-10-15 22:58 465 查看
上周老大让我主持了一个团队技术培训的会议,会议的内容是Handler技术的整体使用流程,包括从Java端到Native端的分析。借此机会,写成一篇文章记录一下成果。若有不足之处,希望大家可以指出,欢迎互相讨论,谢谢。

Java层中的消息生成是从用户创建的Message对象而来的,它是一个由Runnable封装过的对象。或者从Message Pool调用getsMessage派生得来的,而Message Pool是指消息类Message循环队列,这个队列可以容纳的最大Message数量是MAX_POOL_SIZE=50。



既然说到了Message,那么就有必要提一下Looper,Handler,MessageQuene和Message之间的关系了。



总结如下:

一个Thread仅对应一个Looper;而一个Looper对象只对应一个MessageQueue;另外,一个MessageQueue对应多个Messsage;一个Message只对应一个Handler

所以我们得出的结论是:一个Thread可以对应多个Handler

MessagePool是一个循环队列,当Message的数量超过50个的时候,则会回到队头并请空该Message,为了下一次复用。

BlockingRunnable

先上代码:

private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;

public BlockingRunnable(Runnable task) {
mTask = task;
}

@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}

public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}

synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}


BlockingRunnable是在“包装器”构造函数中传递的Runnable 的任务,而对BlockingRunnable的postAndWait调用执行以下操作:

锁定交付BlockingRunnable的线程

如果交付BlockingRunnable失败,则返回false

消息传递和处理

获取消息后,会通过Handler中sendMessageAtTime方法调用MessageQueue的enqueueMessage,并将消息传递给MessageQueue。

Handler的创建

public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

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;
}

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


主要完成的任务:

获取当前的Handler类

如果声明的程序是匿名内部类,成员类或局部类,并且处理程序的修饰符不是静态的。那么会打印出日志,提示可能会发生内存泄漏。

Looper

private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}

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));
}


参数介绍:

sMainLooper:Looper使用主线程

mQueue:与Looper关联的MessageQueue

mThread:与Looper关联的线程

sThreadLocal:线程局部变量key

由此我们可以看到一个线程对应一个Looper,一个Looper对应一个MessageQueue

消息的分发

public static void loop() {
……

for (;;) {
Message msg = queue.next(); // might block

……

try {
msg.target.dispatchMessage(msg);
} finally {
……
}

……

msg.recycleUnchecked();
}
}


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


在为其他线程创建Looper后,调用loop()将执行以下操作:

在MessageQueue中循环获取消息

将消息通过Handler的dispatchMessage方法分配给相应的Handler

清空消息,并将其回收到Message Pool中供下次使用

在Handler的dispatchMessage中:

如果Message设置了回调,则将Message传递给Message的回调处理

如果Handler设置了回调,则将Message先交给Handler的回调方法处理。否则,将消息交给Handler的handleMessage处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android java
相关文章推荐