Handler机制(java层)

Handler、MessageQueue、Looper之间的关系

每个线程只会有一个Looper对象。Handler的创建是和Looper的创建在同一线程中,Looper内部维护了一个MessageQueue(消息队列),该队列内部是通过单链表的形式实现的。Handler通过sendMessage()将消息发送到Looper对应的MessageQueue中,Looper通过消息循环获取消息后,会调用对应消息的target(发消息的Handler)的dispatchMessage()来处理消息。
image

Looper的工作原理

Looper在消息机制中扮演着消息循环的角色,它会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。当我们在主线程创建Handler时,它会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。
几个主要的方法:

  • Looper.prepare():为当前线程创建一个Looper
  • Looper.loop():开启消息循环
  • Looper.getMainLooper():获取到主线程的Looper
  • Looper.quit():清空消息,直接退出Looper
  • Looper.quitSafely():设定一个退出标记,把消息队列中已有的消息(非延迟的消息)处理完毕后才安全地退出

子线程就需要在处理完消息之后退出 Looper,否则该子线程也将不会终止。

Looper # prepare()

对该ThreadLocal放入了新创建的Looper对象

    public static void prepare() {
        prepare(true);
    }

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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));
    }

在构造方法中会创建与之关联的消息队列(MessageQueue),将当前线程的对象保存

final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {

    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

Looper # loop()

loop()不会自动退出,只有MessageQueue的next方法返回null才会跳出循环,当消息队列被标记为退出状态(Looper#quit() 或者 Looper#quitSafely()调用MessageQueue#quit(boolean)),next()就会返回null。否则即使MessageQueue是空的也会阻塞等待。

 public static void loop() {
        // myLooper()会从ThreadLocal中获取到当前线程的Looper
        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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        // 一直循环去获取消息队列中的消息
        for (;;) {
            // next是一个阻塞操作,当没有消息时,next会一直阻塞在那里
            Message msg = queue.next(); // might block
            
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // ...
            
            try {
                // 有消息就处理这条消息
                //  msg.target是发送这条消息的Handler对象
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            
            // ...
            
            // 将msg放入回收对象池中,obtain是去复用这些对象
            msg.recycleUnchecked();
        }
    }

主线程的Looper不会一直阻塞,app进程中不会只有一个线程,会有绘制事件,传感器事件等通过handler发送到主线程中,然后唤醒阻塞。当往Android应用程序的消息队列中加入新的消息时,会同时往管道中的写端写入内容,通过这种方式就可以唤醒正在等待消息到来的应用程序主线程从管道读端返回。
main方法只是做了消息循环,那么我们Activity的生命周期的方法是怎么执行的呢?
在ActivityThread中有个Handler,Activity(四大组件)的生命周期方法在里面均有case,也就说是我们的代码其实就是在这个循环里面去执行的,自然不会阻塞了。
Android中为什么主线程不会因为Looper.loop()里的死循环卡死?
ActivityThread 并不是一个 Thread,就只是一个 final 类

主线程消息循环模型

ActivityThread通过ApplicationThread和AMS进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到ActivityThread中去执行(即切换到主线程)
image

MessageQueue的工作原理

主要包含两个操作:插入(enqueueMessage)和读取(next),读取会伴随删除

MessageQueue # enqueueMessage()

enqueueMessage()会判断target不为null

    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
        
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            // 设置msg正在使用
            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            
            // 如果队列中没有message或该message的执行时间为0或小于第一个message时间
            // 将该message作为队列的头,并更新头message记录
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            // 否则遍历队列,将message插入到合适的位置,整个队列是按message的when字段从小到大排列的,如果两个message的when相同,先入队列的排前面
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            // 需要唤醒的话
            if (needWake) {
                // 此处唤醒了MessageQueue的next()
                nativeWake(mPtr);
            }
        }
        return true;
    }

MessageQueue # next()

异步消息是在Handler构造函数中指定该Handler发送的消息是否为异步

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        // 如果Looper已经退出(调用了dispose()方法后mPtr=0)
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        // 记录空闲时需要处理的IdleHandler数量
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        // 表示距离处理下一个消息的时间,只要大于0就表明还有消息等待处理
        int nextPollTimeoutMillis = 0;
        
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                // 刷新Binder命令
                Binder.flushPendingCommands();
            }
            
            // 调用native层,如果返回了就说明可以从队列中取出一条消息
            // 如果消息队列中没有消息就阻塞等待,靠enqueueMessage()中最后一步调用nativeWake()来唤醒该方法
            nativePollOnce(ptr, nextPollTimeoutMillis);


            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                // (手机睡眠的时间不包括在内)
                // 代表自系统启动开始到调用该方法时度过的毫秒数
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                // 队列头
                Message msg = mMessages;
                
                // 我们可以通过postSyncBarrier(MessageQueue中的方法)往消息队列中插入一个Barrier(此message没有设置target),
                // 那么队列中执行时间在这个Barrier以后的同步消息都会被这个Barrier拦截住无法执行直到我们移除Barrier,而异步消息则没有影响,消息默认就是同步消息
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    // 循环遍历出第一个异步消息
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                
                // 不是Barrier
                if (msg != null) {
                    // 如果时间还没到
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        // quitSafely()依然会执行到这
                        return msg;
                    }
                } else {
                    // No more messages.
                    // msg==null,没有其他消息
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                // 正在退出,返回null
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // 判断如果这是第一次循环(只有第一次会小于0)并且队列为空或还没到处理第一个的时间
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    // 置为阻塞状态
                    mBlocked = true;
                    continue;
                }

                // 初始化最少四个要被执行的IdleHandler
                if (mPendingIdleHandlers == null) {
                    // 临时的IdleHandler数组,每次使用完都会置空
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            // 循环执行所有的IdleHandler,根据返回值判断是否保留
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    // 为false则执行完毕之后移除这条消息
                    // 为true则保留,等到下次空闲时会再次执行
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            // IdleHandler只可能会在第一遍循环去执行
            // IdleHandler只会在消息队列阻塞之前执行一次,之后不会执行直到下一次被调用next()
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

消息机制的唤醒

受到needWake这个变量的影响,在enqueueMessage()中,needWake == true是在两个条件下:

  • 如果当前消息能排在消息队列的头部,needWake = mBlocked(mBlocked会在当前消息队列中没有消息处理,且没有空闲任务的条件下为true)
  • 如果当前mBlocked=true(第一个条件判断),且消息队列头部消息是屏障消息,同时当前插入的消息为异步消息的条件。needWake = true

在next()中,mBlocked = true的条件是在消息队列中没有消息可以处理,且也没有空闲任务的情况下。也就是当前mBlocked = true会影响到MessageQueue中enqueueMessage()方法是否唤醒主线程。

IdleHandler

本质就是趁着消息队列空闲的时候干点事情(非必须事件),idler.queueIdle()里面执行的代码不能太耗时,太耗时会影响后面message的执行。可以用在页面启动优化,做onResume()中非必须的事情。MessageQueue通过使用addIdleHandler(IdleHandler handler)方法添加空闲时任务

Barrier

同步屏障为Handler消息机制增加了一种简单的优先级机制,异步消息的优先级要高于同步消息。在View刷新时用到,保证它被优先处理

Handler的工作原理

Handler与Looper进行关联

Handler发消息最后会发送到对应的Looper下的MessageQueue中,那它们是怎么进行关联的?
Handler的构造函数如下:

  //不带Looper的构造函数
  public Handler() {this(null, false);}
  public Handler(boolean async) {this(null, async);}
  public Handler(Callback callback) {this(callback, false);}
  public Handler(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());
            }
        }
		//Looper.myLooper()内部会调用sThreadLocal.get(),获取线程中保存的looper局部变量
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
            
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
	    //获取当前Looper中的MessageQueue
        mQueue = mLooper.mQueue;
        //
        mCallback = callback;
        mAsynchronous = async;
    }
    
 //带Looper参数的构造函数
  public Handler(Looper looper) { this(looper, null, false); }
  public Handler(Looper looper, Callback callback) { this(looper, callback, false);}
  public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        //获取当前Looper中的MessageQueue
        mQueue = looper.mQueue;
        //
        mCallback = callback;
        mAsynchronous = async;
  }  

在不带Looper参数的构造函数中,通过Looper.myLooper()获取当前Looper对象,也就是说Handler获取的Looper对象是与当前实例化Handler的线程相关的,如果在主线程创建Handler,获取的就是主线程的Looper(HandlerThread继承Thread,无需手动创建Looper)

Handler发送消息

send方法系列主要接收Message对象,而post方法系列则是runnable,但最终也是封装成了message对象

//发送及时消息
public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public final boolean post(Runnable r)

//发送延时消息
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public final boolean postDelayed(Runnable r, long delayMillis)

//发送定时消息
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)

sendMessage()

public final boolean sendMessage(Message msg)
{
    return sendMessageDelayed(msg, 0);
}

sendMessageDelayed()

System.currentTimeMillis(),这个值是一个强关联系统时间,我们可以通过修改系统时间达到修改该值的目的。

public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

sendMessageAtTime()

public boolean sendMessageAtTime(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);
}

enqueueMessage()

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // uptimeMillis就是msg.when
        // 调用了MessageQueue的enqueueMessage()
        return queue.enqueueMessage(msg, uptimeMillis);
}

sendEmptyMessageDelayed()

此方法和前面的都不一样,它没有传入message对象,

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
}

post()

虽然传入的是runnable,但是同样构造了message,调用send方法

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

Handler处理消息

dispatchMessage()

public void dispatchMessage(Message msg) {
    // ①判断有没有调用post()传入的runnable,优先级最高
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        // ②判断mCallback,这个callback是在某些带有Callback参数的Handler构造函数中传入的
        if (mCallback != null) {
            // 可以返回false
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // ③交给Handler的handleMessage()去处理
        handleMessage(msg);
    }
}

handleCallback()

private static void handleCallback(Message message) {
    message.callback.run();
}

Message

里面有Bundle成员变量

  • what:用户定义的消息代码,消息是关于什么的。每个handler各自包含自己的消息代码,所以不用担心自定义的消息跟其他handlers有冲突(msg.target不同)
  • arg1/arg2:只想存很少的整型数据,如果需要传输很多,可以使用Message中的setData(Bundle bundle)
  • obj:发送给接受方的任意对象(在使用跨进程时注意obj不能为null)
  • replyTo:在使用跨进程通信Messenger时,可以确定需要谁来接收(Messenger)
private static final Object sPoolSync = new Object();//控制获取从消息池中获取消息。保证线程安全,锁
private static Message sPool;//消息池
private static int sPoolSize = 0;//消息池中的消息数量
private static final int MAX_POOL_SIZE = 50;//消息池最大容量

从消息池获取消息是线程安全的。

obtain() :从消息池中获取消息

官方建议使用Message.obtain()系列方法来获取Message实例,因为其Message实例是直接从Handler的消息池中获取的,可以循环利用,不必另外开辟内存空间,效率比直接使用new Message()创建实例要高。
在Message的obtain带参数的方法中,内部都会调用无参的obtain()方法来获取消息后。然后并根据其传入的参数,对Message进行赋值。

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;// 消息头结点
            sPool = m.next; // 头往下移动
            m.next = null;
            m.flags = 0; // clear in-use flag 清除使用中标志
            sPoolSize--;
            return m; // 移除头结点
        }
    }
    // 只有在消息池里取不出Message才去new
    return new Message();
}

消息池内部实现是以链表的形式。
image

recycleUnchecked():回收消息到消息池

void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        // 用于表示当前message消息已经被使用过了
        flags = FLAG_IN_USE;
        // 清空之前的数据
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this; // 将消息存储在消息池中
                sPoolSize++;
            }
        }
}

这种添加删除的方式就像栈的先进后出。
image

消息回收的时机

  • 当Handler指定删除单条消息,或所有消息的时候
  • 当Looper取出消息时,loop()
  • 当Looper取消循环消息队列的时候
  • 当消息队列退出,但是仍然发送消息过来的时候enqueueMessage()

主线程的Looper对象的创建

主线程的Looper在ActivityThread里创建,ActivityThread是Android的启动类,main方法就在里面

main()

//android.app.ActivityThread
public final class ActivityThread {
    ...
    public static void main(String[] args) {
         
        //...
    
        // 这里创建了主线程的Looper
        Looper.prepareMainLooper();
    
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
    
        // 这个Handler就是ActivityThread.H
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
    
        AsyncTask.init();
    
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        // 开启消息循环
        Looper.loop();
        // 当main方法结束了,你的程序也就退出了
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
    
}

MainLooper可以用来做什么?

  • 判断当前线程是否为主线程(Looper.myLooper() == Looper.getMainLooper())
  • 创建运行在主线程的Handler( mHandler = new Handler(Looper.getMainLooper()))

prepareMainLooper()

 /**
     * 为UI线程初始化Looper对象并创建消息队列
     */
    public static void prepareMainLooper() {
        // prepare(boolean quitAllowed)
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }


H

class H extends Handler {
        public static final int BIND_APPLICATION        = 110;
        public static final int EXIT_APPLICATION        = 111;
        public static final int RECEIVER                = 113;
        public static final int CREATE_SERVICE          = 114;
        public static final int SERVICE_ARGS            = 115;
        public static final int STOP_SERVICE            = 116;

        public static final int CONFIGURATION_CHANGED   = 118;
        public static final int CLEAN_UP_CONTEXT        = 119;
        public static final int GC_WHEN_IDLE            = 120;
        public static final int BIND_SERVICE            = 121;
        public static final int UNBIND_SERVICE          = 122;
        public static final int DUMP_SERVICE            = 123;
        public static final int LOW_MEMORY              = 124;
        public static final int PROFILER_CONTROL        = 127;
        public static final int CREATE_BACKUP_AGENT     = 128;
        public static final int DESTROY_BACKUP_AGENT    = 129;
        public static final int SUICIDE                 = 130;
        public static final int REMOVE_PROVIDER         = 131;
        public static final int ENABLE_JIT              = 132;
        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
        public static final int SCHEDULE_CRASH          = 134;
        public static final int DUMP_HEAP               = 135;
        public static final int DUMP_ACTIVITY           = 136;
        public static final int SLEEPING                = 137;
        public static final int SET_CORE_SETTINGS       = 138;
        public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
        public static final int DUMP_PROVIDER           = 141;
        public static final int UNSTABLE_PROVIDER_DIED  = 142;
        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
        public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
        public static final int INSTALL_PROVIDER        = 145;
        public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
        public static final int ENTER_ANIMATION_COMPLETE = 149;
        public static final int START_BINDER_TRACKING = 150;
        public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
        public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
        public static final int ATTACH_AGENT = 155;
        public static final int APPLICATION_INFO_CHANGED = 156;
        public static final int RUN_ISOLATED_ENTRY_POINT = 158;
        public static final int EXECUTE_TRANSACTION = 159;
        public static final int RELAUNCH_ACTIVITY = 160;
        //...
}

ActivityThread中还有Idler,Idler将为那些已经完成onResume的Activity调用AMS的activityIdle函数。触发内存回收机制?该函数是Activity成功创建并启动的流程中与AMS交互的最后一步。虽然对应用进程来说,Idler处理的优先级最低,但AMS似乎不这么认为,因为它还设置了超时等待,以处理应用进程没有及时调用activityIdle的情况。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值