美文网首页
Android任务管理机制

Android任务管理机制

作者: _喝喝酒吹吹风_ | 来源:发表于2020-09-20 14:58 被阅读0次

    概述

    消息机制涉及MessageQueue/Message/Looper/Handler这4个类。

    说明
    • Message:消息分为硬件产生的消息(如按钮、触摸)和软件生成的消息;,Message有自己的缓存池,避免message的频繁创建销毁
    • MessageQueue:消息队列的主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
    • Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
    • Looper:不断循环执行(Looper.loop),按分发机制将消息分发给目标处理者。
    类关系
    • Looper有一个MessageQueue消息队列;
    • MessageQueue有一组待处理的Message;
    • Message中有一个用于处理消息的Handler;
    • Handler中有Looper和MessageQueue;
    ThreadLocal
    • 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。
    • 每个线程可以有多个TLS,一个TLS对应一个value
    • Looper 创建就以TLS方式创建,一个线程中最多只能有1个Looper
    主线程驱动
    • 主线程最终就是调用Looper的loop方法进入死循环,进行消息驱动
    • 主线程的Looper 是在 ActivityThread main函数中创建的
    public static void main(String[] args) {
            // Install selective syscall interception
            AndroidOs.install();
    
            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);
    
            Environment.initForCurrentUser();
    
            // Make sure TrustedCertificateStore looks in the right place for CA certificates
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
    
            Process.setArgV0("<pre-initialized>");
    
            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"));
            }
    
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    
    • 消息生产
      • handler::enqueueMessage,MessageQueue是按照Message触发时间的先后顺序排列的,队头的消息是将要最早触发的消息。当有消息需要加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序。
    • 消息消费(在loop中)
      • 读取MessageQueue的下一条Message;
    Message next() {
        final long ptr = mPtr;
        if (ptr == 0) { //当消息循环已经退出,则直接返回
            return null;
        }
        int pendingIdleHandlerCount = -1; // 循环迭代的首次为-1
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            //nativePollOnce是阻塞操作,其中nextPollTimeoutMillis代表下一个消息到来前,还需要等待的时长;当nextPollTimeoutMillis = -1时,表示消息队列中无消息,会一直等待下去。
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //当消息的Handler为空时,则查询异步消息
                if (msg != null && msg.target == null) {
                    //当查询到异步消息,则立刻退出循环
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        //当异步消息触发时间大于当前时间,则设置下一次轮询的超时时长
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // 获取一条消息,并返回
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        //设置消息的使用状态,即flags |= FLAG_IN_USE
                        msg.markInUse();
                        return msg;   //成功地获取MessageQueue中的下一条即将要执行的消息
                    }
                } else {
                    //没有消息
                    nextPollTimeoutMillis = -1;
                }
                //消息正在退出,返回null
                if (mQuitting) {
                    dispose();
                    return null;
                }
                //当消息队列为空,或者是消息队列的第一个消息时
                if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    //没有idle handlers 需要运行,则循环并等待。
                    mBlocked = true;
                    continue;
                }
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }
            //只有第一次循环时,会运行idle handlers,执行完成后,重置pendingIdleHandlerCount为0.
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; //去掉handler的引用
                boolean keep = false;
                try {
                    keep = idler.queueIdle();  //idle时执行的方法
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
            //重置idle handler个数为0,以保证不会再次重复运行
            pendingIdleHandlerCount = 0;
            //当调用一个空闲handler时,一个新message能够被分发,因此无需等待可以直接查询pending message.
            nextPollTimeoutMillis = 0;
        }
    }
    
    • 把Message分发给相应的target;
    • 再把分发后的Message回收到消息池,以便重复利用。
    IdleHandler

    每次在获取下一个message时,没有获取到时执行idleHnalder的runable

    整体流程
    handler_java.jpg
    • Handler通过sendMessage()发送Message到MessageQueue队列;
    • Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
    • 经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。
    • 将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。

    Native 层 消息机制

    在整个消息机制中,而MessageQueue是连接Java层和Native层的纽带,换言之,Java层可以向MessageQueue消息队列中添加消息,Native层也可以向MessageQueue消息队列中添加消息,接下来来看看MessageQueue。


    handler_arch.png
    • 红色虚线关系:Java层和Native层的MessageQueue通过JNI建立关联,彼此之间能相互调用,搞明白这个互调关系,也就搞明白了Java如何调用C++代码,C++代码又是如何调用Java代码。
    • 蓝色虚线关系:Handler/Looper/Message这三大类Java层与Native层并没有任何的真正关联,只是分别在Java层和Native层的handler消息模型中具有相似的功能。都是彼此独立的,各自实现相应的逻辑。
    • WeakMessageHandler继承于MessageHandler类,NativeMessageQueue继承于MessageQueue类

    MessageQueue通过mPtr变量保存NativeMessageQueue对象,从而使得MessageQueue成为Java层和Native层的枢纽,既能处理上层消息,也能处理native层消息;下面列举Java层与Native层的对应图

    另外,消息处理流程是先处理Native Message,再处理Native Request,最后处理Java Message。理解了该流程,也就明白有时上层消息很少,但响应时间却较长的真正原因。

    • Native Message:和java层类似,由native的
    • Native Request: 由fd触发的event,这些文件描述符可以让其他组件注册,发送

    refrence

    https://www.jianshu.com/p/f7cabfe19720
    Android Handler 通信 - 彻底了解 Handler 的通信过程

    Android Handler:手把手带你深入分析 Handler机制源码

    相关文章

      网友评论

          本文标题:Android任务管理机制

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