美文网首页程序员
Android 消息机制

Android 消息机制

作者: 卖炭少年炭治郎 | 来源:发表于2020-09-11 16:11 被阅读0次

    主线程Looper创建的位置

    ActivityThread的main方法中,也就是消息机制开始建立的地方

    
            Looper.prepareMainLooper();
    
            // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
            // It will be in the format "seq=114"
            long startSeq = 0;
            if (args != null) {
                for (int i = args.length - 1; i >= 0; --i) {
                    if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                        startSeq = Long.parseLong(
                                args[i].substring(PROC_START_SEQ_IDENT.length()));
                    }
                }
            }
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    

    1. 调用了Looper.prepareMainLooper()方法,内部又调用了prepare()方法

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

    可以看到,new了一个looper对象,存到了sThreadLocal中。

    2. 调用new Looper(quitAllowed)构造方法,创建了MessageQueue消息队列。

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

    3. thread.getHandler()方法,拿到H(),其实也就是拿到Handler对象。

    new了ActivityThread对象,此时H()对象也随着创建出来。

       ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    

    H()对象其实也就是Handler对象,调用了handler的无参构造

    public Handler() {
            this(null, false);
        }
    

    最终调用如下代码,完成了H()对消息队列和Looper的引用的持有。

    public Handler(@Nullable 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 " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
            }
            mQueue = mLooper.mQueue;
            mCallback = callback;
            mAsynchronous = async;
        }
    

    4. 调用Looper.loop()开启死循环,至此Android的消息机制开启

    myLooper()会取出ThreadLocal里存储的Looper对象,并取出Looper中的消息队列,然后死循环,开始从消息队列中取消息,通过msg.target(也就是发送消息的handler对象)的dispatchMessage()方法,把消息交给handler去处理。

    /**
         * Run the message queue in this thread. Be sure to call
         * {@link #quit()} to end the loop.
         */
        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 (;;) {
                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);
                }
    
                try {
                    msg.target.dispatchMessage(msg);
            
                } catch (Exception exception) {
                    if (observer != null) {
                        observer.dispatchingThrewException(token, msg, exception);
                    }
                    throw exception;
                } finally {
                    ThreadLocalWorkSource.restore(origWorkSource);
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
              
                ...
    
                msg.recycleUnchecked();
            }
        }
    

    总结

    • 一个线程中只允许有一个Looper和消息队列

    原因:1.代码限制;2.多个会导致混乱

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

    Looper构造方法内创建了一个消息队列,多了不利于维护。

    • 一个线程中可以有多个Handler对象

    • 线程间通过可以Handler在A,B之间通信是因为Handler在A线程创建时候,持有了A的Looper和消息队列,B线程持有了A的引用,所以可以通过Handler发送消息给A。

    相关文章

      网友评论

        本文标题:Android 消息机制

        本文链接:https://www.haomeiwen.com/subject/qmkbektx.html