zoukankan      html  css  js  c++  java
  • 消息机制——handler

    android消息机制——handler

    为啥要有消息机制?

    android有个主线程,activityThread,可以操作UI,其他线程不能更新UI。APP开发过程中经常遇到耗时操作,如文件读写,网络请求等。如果把这些耗时请求都放在主线程上面,会发生ANR(Application Not Responding)。针对这种情况,一般的解决措施都是另开个线程去执行这些耗时操作,当这些耗时操作执行完,需要更新UI,咋办?这个时候消息机制就可以大显身手,发送message,告诉主线程,去更新UI。

    ANR?

    三种类型:

    • KeyDispatchTimeout(5 seconds) ——按键或触摸事件在特定时间内无响应
    • BroadcastTimeout(10 seconds) ——BroadcastReceiver在特定时间内无法处理完成
    • ServiceTimeout(20 seconds) ——Service在特定的时间内无法处理完成

    两种原因:

    • 当前事件没有及时完成
    • 当前事件迟迟没有被处理

    Handler如何成为通讯员?

    ActivityThread被创建时会创建looper,lopper的构造方法里面创建MessageQueue。

    • Handler的send与post都会sendMessage,执行enQueueMessage方法,向MessageQueue中插入一条message。
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
            msg.target = this;
            if (mAsynchronous) {
                msg.setAsynchronous(true);
            }
            return queue.enqueueMessage(msg, uptimeMillis);
    }
    
    • looper会不断轮询QueueMessage的next方法。
    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;
    
            // Make sure the identity of this thread is that of the local process,
            // and keep track of what that identity token actually is.
            Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
    
            for (;;) {
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                // This must be in a local variable, in case a UI event sets the logger
                final Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                }
    
                final long traceTag = me.mTraceTag;
                if (traceTag != 0) {
                    Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
                }
                try {
                    msg.target.dispatchMessage(msg);
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
    
                if (logging != null) {
                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                }
    
                // Make sure that during the course of dispatching the
                // identity of the thread wasn't corrupted.
                final long newIdent = Binder.clearCallingIdentity();
                if (ident != newIdent) {
                    Log.wtf(TAG, "Thread identity changed from 0x"
                            + Long.toHexString(ident) + " to 0x"
                            + Long.toHexString(newIdent) + " while dispatching to "
                            + msg.target.getClass().getName() + " "
                            + msg.callback + " what=" + msg.what);
                }
    
                msg.recycleUnchecked();
            }
        }
    
    • 发现message,就会执行handler中的dispathMessage,dispathMessage被调用后,调用handlerMessage方法。
    try {
        msg.target.dispatchMessage(msg);
    } finally {
        if (traceTag != 0) {
            Trace.traceEnd(traceTag);
        }
    }
    
    public void dispatchMessage(Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    随便提下

    当 MessageQueue中没有message且没有空闲的handler可以处理的时候,通过nativePollOnce将循环阻塞与此。enqueueMessage后,再重新通过nativeWake唤醒。

  • 相关阅读:
    BZOJ4416 [Shoi2013]阶乘字符串 【序列自动机 + 状压dp】
    BZOJ2159 Crash 的文明世界 【第二类斯特林数 + 树形dp】
    快速求原根
    BZOJ2530 [Poi2011]Party 【贪心】
    BZOJ2213 [Poi2011]Difference 【乱搞】
    BZOJ2276 [Poi2011]Temperature 【单调队列】
    多项式除法
    loj2538 「PKUWC2018」Slay the Spire 【dp】
    loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】
    Java多线程之线程的暂停
  • 原文地址:https://www.cnblogs.com/qinhe/p/6370838.html
Copyright © 2011-2022 走看看