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唤醒。

  • 相关阅读:
    Linux学习之telnet命令
    Linux学习netstat
    php 将字符串中的连续多个空格转换为一个空格
    erlang: Programming Rules and Conventions。
    jQuery.data() 方法
    检测一个DOM对象是否为空
    PHP 根据类名和方法名已面向对象的方式执行函数。
    PHP函数前面的@。
    php涉及数据库操作时响应很慢。
    Apache实现动态虚拟主机
  • 原文地址:https://www.cnblogs.com/qinhe/p/6370838.html
Copyright © 2011-2022 走看看