Android消息机制的原理及源码解析 - 简书 (jianshu.com)
Android Handler 消息机制(解惑篇)
Handler 都没搞懂,拿什么去跳槽啊?
郭霖 android异步消息处理机制完全解
1.ActivityThread.main
public static void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);//把ApplicationThread对象给到AMS
Looper.loop();
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
//新建Looper对象,并在构造方法中新建MessageQueue对象,把Looper对象放到存放到ThreadLocal类所在的ThreadMap中,以当前线程为key,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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public static @Nullable Looper myLooper() {
return sThreadLocal.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();
}
2.Handler的基本用法
Handler handler=new Handler(){
public void handleMessage(Message msg){
//接收并处理消息
}
}
handler.post(runnable);
handler.sendMessage(msg);
3.Hanlder和Looper进行关联
Handler构造方法,通过myLooper方法从ThreadLocal所在的ThreadMap中,根据当前的线程(作为key值)从ThreadMap中Looper对象,根据Looper对象得到MessageQueue对象,便于Handler发送消息时,可以把消息添加到MessageQueue对象中.
public Handler(Callback callback,boolean async){
mLooper=Looper.myLooper();
mQueue=mLooper.mQueue;
}
4.Handler.sendMessage或者Handler.post(runable)解析
(1).Hanlder.post也是runnable封装成Message对象
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
(2).Handler.sendMessage最终会把消息添加到消息队列
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
5.Looper.loop开启死循环
//Looper
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
for (;;) {
// 不断从 MessageQueue 获取 消息
Message msg = queue.next(); // might block
//退出 Looper
if (msg == null) {
return;
}
try {
msg.target.dispatchMessage(msg);// msg.target就是Handler
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
}
}
}
6.Handler.dispatchMessage
//Handler
public void dispatchMessage(Message msg) {
//msg.callback 是 Runnable ,如果是 post方法则会走这个 if
if (msg.callback != null) {
handleCallback(msg);
} else {
//callback 见【3.4】
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//回调到 Handler 的 handleMessage 方法
handleMessage(msg);
}
}
7.Handler延伸
(1).为什么主线程不会因为Looper.loop()里面的死循环卡死?
handler机制是使用管道来实现的,主线程没有消息处理时,也就是当queue.next获取消息时,
nativePollOnce,底层阻塞在管道读取端,主线程进入休眠状态,释放CPU资源,而不会一直去执行for循环,直到,MsgQueue里面有消息被添加进来,调用nativeWeak(),底层管道写端写入数据,唤醒主线线程.
(2).Hanlder引起的内存泄漏原因以及最佳解决方案。
Handler允许我们发送延迟消息,如果在延时期间,用户关闭了Activity,那么Activity会泄露。
原因:Message(target)持有Handler,Handler作为内部类,持有外部类Activity,最终导致Activity内存泄漏。
解决该问题最有效的方法是:将Handler定义为静态内部类,在内部持有Activity的弱引用,并及时移除所有消息。
public static class SafeHandler extends Handler{
private WeakReference<HandleActivity> ref;
public SafeHandler(HandlerActivity activity){
ref=new WeakReference<HandleActivity>();
}
public void handleMessage(final Message mes){
HandleActivity activity=ref.get();
if(activity!=null){
activity.handleMessage(msg);
}
}
}
(3).子线程里面如何使用Handler
new Thread(new Runnable(){
public void run(){
//新建一个Looper对象,把当期线程作为key值,存储到ThreadLocal类中的ThreadLocalMap中.
Looper.prepare();
//构造方法中根据当期线程,得到Looper对象,然后从Looper对象得到MsgQueue
Handler handler=new Handler();
handler.post(new Runable(){
public void run() {
// 在这里执行你需要在子线程中完成的任务
}
});
//启动消息循环
Looper.loop();
}
}).start();
(4).在子线程中进行UI操作的方式.
Handler.post(runnable)
View.post
Activity.runOnUiThread