深入理解Handler源码框架(你要知道的那点事)

1 前言

​ 在《深入理解Handler源码框架(Android情报系统)》这篇文章中详细描述了Handler框架的实现原理以及应用场景。本文将在理解Handler架构基础上,定位源码,详细解析Handler在Android系统中的重要作用。

​ 1)Looper.loop()为什么不会引起ANR?

​ 2)Message如何防止OOM和内存抖动?

​ 3)Handler在Android系统中有哪些应用?
深入理解Handler源码框架(Android情报系统)

2 Message享元模式

​ Message 引起OOM似乎还没有遇到过,但是Message 要占用内存就有可能引起这个问题,平时使用时候注意点就行了。这里主要讲一下Message的享元模式。

​ 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。

​ 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。Message 就是利用了享元模式来实现内存复用,先看一下源码。

​ 当我们调用Message.obtain(),如果消息池sPool不为空,则选择sPool的第一个消息进行复用,否则创建一个新消息。这也是Message防止内存抖动的方法

​ 请注意:sPool里的消息是通过recycleUnchecked()处理后可复用的消息,并不是正在使用的消息,否则直接复用正在使用消息,会引起致命错误。

请拿出小本本记下来:使用Message是使用Message.obtain()函数来创建对象

public final class Message implements Parcelable {

    public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    
    Message next;
    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;
    public Message() {
    }
    
    /** @hide */
    public static final Object sPoolSync = new Object();
    
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    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;
            }
        }
        return new Message();
    }
    
    /**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
    @UnsupportedAppUsage
    void recycleUnchecked() {
        // Mark the message as in use while it remains in the recycled object pool.
        // Clear out all other details.
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
    ……

}

3 你可能不知道的那点事

​ 上篇文章中我们讲了Handler主要用于线程间的通信,而我们平时可能主要用于子线程向主线程发送消息从而更新UI。这个实际应用表明了什么?至少说明Activity是工作在主线程的(其实Service也是工作在主线程的),也就说明其实APP能够正常运行,Handler框架在这里起到了很重要的作用。听起来是这么回事,但是源码如何实现的呢?下面我们慢慢道来,首先了解下Android的启动流程,如下图所示,System Server 是启动APP的基础。

clipboard.png

​ System Server 是Zygote进程 fork 的第一个Java 进程。SystemServer是Android系统的核心之一,大部分Android提供的服务都运行在这个进程里,SystemServer中运行的服务总共有80多种。为了防止应用进程对系统造成破坏,Android的应用进程没有权限直接访问设备的底层资源,只能通过SystemService中的代理访问。通过Binder,用户进程在使用SystemService中的服务并没有太多不便变之处。(PS:Binder是Android进程通信的重要机制,以后会进行讲解

​ 下面源码可以看到SystemServer()的构函数并没有做什么工作,因此还需要看下run()函数做了哪些工作。

    /**
     * The main entry point from zygote.
     */
    public static void main(String[] args) {
        new SystemServer().run();
    }
    

    public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
        mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
        mRuntimeStartUptime = SystemClock.uptimeMillis();
    }

​ System Server启动流程集中于run()函数,主要做了以下工作:(划重点Looper)

  • ​ 配置环境参数,比如系统时间、默认时区、语言、load一些Library等等;
  • ​ 启动系统线程,比如 ”UI thread”, “InputReader”, “InputDispatch” 等;
  • ​ 启动系统服务:AMS、WMS、PMS等80多种系统服务;
  • ​ 初始化Looper:这里初始化主线程使用的Looper。

​ 看一下源码run()函数。大家可以看到熟悉的Looper,Handler框架是从此时就开始应用了。

Looper.prepareMainLooper();

Looper.loop();

private void run() {
        try {
            ……
            
            // Prepare the main looper thread (this thread).
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
                    SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            ……

            // Initialize the system context.
            createSystemContext();

            // Create the system service manager.
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
                    mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
        
        // Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

Looper.prepareMainLooper()实现如下,这个函数就是创建主线程的Looper:

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

3.1 APP 主线程

​ 为了更好的理解APP 主线程和Handler框架的关系,首先让我们先了解一下APP的启动流程如下:


image-20200909194038544.png

​ 当我们在手机桌面点击应用图标(优酷APP)时 ,Launcher(桌面应用APP)会通过Binder向AMS请求打开优酷APP,AMS 通过socket向Zygote进行发出请求,zygote进程 创建应用程序进程(优酷),优酷APP进行启动就绪后告知AMS,AMS最终通过ActivityThread启动Activity。根据上图所示,APP 主线程主要指ActivityThread ,因此我们先看一下源码是如何实现的。通过源码可以确定ActivityThread 创建的主线程的Looper和Handler。

   static volatile Handler sMainThreadHandler;  // set once in main()
   
   public static void main(String[] args) {
        ……
        Looper.prepareMainLooper();
        ……
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ……
        Looper.loop();

    }

​ 上面源码中sMainThreadHandler = thread.getHandler();这个sMainThreadHandler 的实现类就是H()。首先看一下BIND_APPLICATION消息做了什么工作。

    class H extends Handler {
        ……
            
        public void handleMessage(Message msg) {
           
            switch (msg.what) {
                case BIND_APPLICATION:

                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case EXIT_APPLICATION:
                    if (mInitialApplication != null) {
                        mInitialApplication.onTerminate();
                    }
                    Looper.myLooper().quit();
                    break;
                ……

                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;


                ……
                case RELAUNCH_ACTIVITY:
                    handleRelaunchActivityLocally((IBinder) msg.obj);
                    break;
            }


        }
    }

​ H()接收到BIND_APPLICATION时调用ActivityThread#handleBindApplication

   private void handleBindApplication(AppBindData data) {
        // Register the UI Thread as a sensitive thread to the runtime.
        VMRuntime.registerSensitiveThread();
        ……
        Application app;
        ……
        try {
            ……
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
            ……
            }
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                ……
            }
        } finally {
            ……
        }

    }

​ handleBindApplication中调用Instrumentatio#makeApplication函数,该函数中根据app信息中Application类的路径加载并创建对象,然后调用Instrumentatio#callApplicationOnCreate函数。

​ callApplicationOnCreate中调用Application对象的onCreate函数。我们在应用开发中常用的Application的onCreate就是这里调用的

public void callApplicationOnCreate(Application app) {
        app.onCreate();
}

​ 现在我们知道了APP启动是这个主线程处理的,那我们熟悉的Activity还没有启动呢!现在让我们来看一下ActivityThread#handleRelaunchActivity函数,这个函数最终会调用ActivityThread#performLaunchActivity

    @Override
    public void handleRelaunchActivity(ActivityClientRecord tmp,
            PendingTransactionActions pendingActions) {
        ……
        handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
    ……
    }
    
    
    private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
            PendingTransactionActions pendingActions, boolean startsNotResumed,
            Configuration overrideConfig, String reason) {
        ……
        handleLaunchActivity(r, pendingActions, customIntent);
    }
    
    
    @Override
    public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) {
        ……
        final Activity a = performLaunchActivity(r, customIntent);
        ……
        return a;
    }
    
    
     /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        ……

        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ……

            if (activity != null) {

                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }

                r.activity = activity;
            }
            r.setState(ON_CREATE);

            mActivities.put(r.token, r);

        } 
        ……

        return activity;
    }

​ ActivityThread#performLaunchActivity函数中主要做了以下几件事
​ 1)创建Activity对象;

​ 2)初始化activity对象的上下文

​ 3)为当前activity创建窗口。

​ 4)调用Instrumentation#callActivityOnCreate。

/**
 * Perform calling of an activity's {@link Activity#onCreate}
 * method.  The default implementation simply calls through to that method.
 *
 * @param activity The activity being created.
 * @param icicle The previously frozen state (or null) to pass through to onCreate().
 */
public void callActivityOnCreate(Activity activity, Bundle icicle) {
    prePerformCreate(activity);
    activity.performCreate(icicle);
    postPerformCreate(activity);
}

​ 通过上文讲解,可以确定ActivityThread实现了Application和Activity的启动工作。其实除了Application和Activity,ActivityThread还对Service 、Receiver、GC等系统组件都进行了相应的管理,而这些工作都是通过Handler框架实现的。

3.2 ANR 和Looper.loop()的关系

3.2.1什么是ANR

​ ANR全称:Application Not Responding,也就是应用程序无响应。

3.2.2 产生原因

Android系统中,ActivityManagerService(简称AMS)WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。

​ 以下四个条件都可以造成ANR发生:

  • InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
  • BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。
  • Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。
  • ContentProvider Timeout :ContentProvider的publish在10s内没进行完。

3.2.3 源码分析

​ 3.2.2描述了四种产生ANR的原因,Looper.loop()即是死循环又是会阻塞,它和ANR的产生有关系吗?其实就相当于你问情报系统会不会引起街头战争一样。唯一的关系是系统通过Handler发送和处理ANR消息。下面通过源码来理解InputDispatching Timeout情况下ANR的产生与处理过程。

​ ActivityManagerService#inputDispatchingTimedOut函数用于检测触摸或者键盘等输入事件是否超时,如果超时了则会通过mHandler发送ANR消息进行处理。这里的mHandler处于主线程。

mHandler = new MainHandler(mHandlerThread.getLooper());

@Override
    public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
        ……

        if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
            return -1;
        }

        return timeout;
    }

    /**
     * Handle input dispatching timeouts.
     * Returns whether input dispatching should be aborted or not.
     */
    public boolean inputDispatchingTimedOut(final ProcessRecord proc,
            final ActivityRecord activity, final ActivityRecord parent,
            final boolean aboveSystem, String reason) {
        

        if (proc != null) {
            ……
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
                }
            });
        }

        return true;
    }

​ AppErrors #appNotResponding用于处理上述四种ANR消息,这里可以看到如果是isSilentANR,则直接杀掉APP,如果是需要显示对话框,则会mService.mUiHandler.sendMessage(msg);其中mService就是ActivityManagerService

mUiHandler = mInjector.getUiHandler(this);

    final void appNotResponding(ProcessRecord app, ActivityRecord activity,
            ActivityRecord parent, boolean aboveSystem, final String annotation) {
        ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
        SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
        ……

        boolean isSilentANR;

        synchronized (mService) {
            ……

        synchronized (mService) {
            mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);

            if (isSilentANR) {
                app.kill("bg anr", true);
                return;
            }

            // Set the app's notResponding state, and look up the errorReportReceiver
            makeAppNotRespondingLocked(app,
                    activity != null ? activity.shortComponentName : null,
                    annotation != null ? "ANR " + annotation : "ANR",
                    info.toString());

            // Bring up the infamous App Not Responding dialog
            Message msg = Message.obtain();
            msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
            msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);

            mService.mUiHandler.sendMessage(msg);
        }
    }

​ 综上所述,AMS首先判断输入事件是否超时,如果超时了mHandler发消息统一处理ANR,如果是需要显示ANR对话框,则mUiHandler发消息给自己,然后弹出对话框。由此可见,loop()不会引起ANR。

​ 这里的mHandler和mUiHandler都是运行在主线程,只是处理的具体事务方向不同。我们平时也可以参考这里不要把所有的消息都用一个handler处理。

3.3 消息机制之同步屏障

​ Message分为3中:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。

​ 我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。

**

    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.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            //1、如果有消息被插入到消息队列或者超时时间到,就被唤醒,否则阻塞在这。
            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;
                //2.第一个消息是屏障消息则会跳过同步消息去寻找下一个异步消息。
                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());
                }
                //找到异步消息或者同步消息的时候
                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) {
                            //3.有屏障消息也就是异步消息处理的时候
                            //将异步消息从mMessages去除  ,同步屏障依旧存在
                            prevMsg.next = msg.next;
                        } else {
                            //普通消息时候,消息队列头直接指向下一个消息
                            //也就是mMessages中移除当前普通消息
                            mMessages = msg.next;
                        }
                        
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                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;
                }

                if (mPendingIdleHandlers == null) {
                    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.
            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 {
                    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.
            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;
        }
    }

3.3.2 同步屏障应用场景

日常的应用开发中,很少会用到同步屏障。那么,同步屏障在系统源码中有哪些使用场景呢?Android 系统中需要优先处理的消息就可以设置为异步消息,然后应用同步屏障机制。由于 UI 更新相关的消息是优先级最高的,在 View 更新时,draw、requestLayout、invalidate 等很多地方都应用了同步屏障。让我们来看一下源码

​ ViewRootImpl#scheduleTraversals函数用于更新UI,首先发送了屏障消息。

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            //设置同步屏障
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
    
    

​ Choreographer#postCallback最终向主线程发送了一个异步消息mHandler.sendMessageAtTime(msg, dueTime);

    public void postCallback(int callbackType, Runnable action, Object token) {
        postCallbackDelayed(callbackType, action, token, 0);
    }
    
        public void postCallbackDelayed(int callbackType,
            Runnable action, Object token, long delayMillis) {
        if (action == null) {
            throw new IllegalArgumentException("action must not be null");
        }
        if (callbackType < 0 || callbackType > CALLBACK_LAST) {
            throw new IllegalArgumentException("callbackType is invalid");
        }

        postCallbackDelayedInternal(callbackType, action, token, delayMillis);
    }
    
        private void postCallbackDelayedInternal(int callbackType,
            Object action, Object token, long delayMillis) {
        if (DEBUG_FRAMES) {
            Log.d(TAG, "PostCallback: type=" + callbackType
                    + ", action=" + action + ", token=" + token
                    + ", delayMillis=" + delayMillis);
        }

        synchronized (mLock) {
            final long now = SystemClock.uptimeMillis();
            final long dueTime = now + delayMillis;
            mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);

            if (dueTime <= now) {
                scheduleFrameLocked(now);
            } else {
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
                msg.arg1 = callbackType;
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, dueTime);
            }
        }
    }

​ 最后,当需要移除同步屏障的时候需要调用 ViewRootImpl#unscheduleTraversals()

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        mChoreographer.removeCallbacks(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

3.4 Fragment添加过程

​ Activity添加Fragment一般通过以下方法来实现,代码很简单。这里我们要通过分析源码来分析一下commit()之后,Avtivity是否立即添加Fragment成功?是与不是对我们开发应用有什么影响?

supportFragmentManager.beginTransaction()
    .add(R.id.nav_host_fragment_container,HomeFragment())
    .commit()

​ 下面直接看源码FragmentManagerImpl#beginTransaction(),这里只是返回BackStackRecord对象。

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

​ FragmentTransaction#add 和FragmentTransaction#replace 最终都是调用FragmentTransaction#doAddOp,因此我们的重点是看doAddOp函数,doAddOp重点是调用了addOp(new Op(opcmd, fragment));这里的cmd是指OP_REPLACE、OP_ADD、OP_ATTACH、OP_DETACH、OP_SHOW、OP_HIDE、OP_REMOVE等

    
    public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment) {
        return replace(containerViewId, fragment, null);
    }
    public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
            @Nullable String tag)  {
        doAddOp(containerViewId, fragment, tag, OP_REPLACE);
        return this;
    }    
    
    
    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        ……
        addOp(new Op(opcmd, fragment));
    }
    

​ FragmentTransaction#addOp其实就是添加fragment到ArrayList<Op> mOps中。这里我们发现一个问题,这里fragment只是放到了容器里和Activity没有半毛钱关系。

static final class Op {
    int mCmd;
    Fragment mFragment;
    int mEnterAnim;
    int mExitAnim;
    int mPopEnterAnim;
    int mPopExitAnim;
    Lifecycle.State mOldMaxState;
    Lifecycle.State mCurrentMaxState;

    Op() {
    }

    Op(int cmd, Fragment fragment) {
        this.mCmd = cmd;
        this.mFragment = fragment;
        this.mOldMaxState = Lifecycle.State.RESUMED;
        this.mCurrentMaxState = Lifecycle.State.RESUMED;
    }

    Op(int cmd, @NonNull Fragment fragment, Lifecycle.State state) {
        this.mCmd = cmd;
        this.mFragment = fragment;
        this.mOldMaxState = fragment.mMaxState;
        this.mCurrentMaxState = state;
    }
}

ArrayList<Op> mOps = new ArrayList<>();
……

ArrayList<Runnable> mCommitRunnables;

void addOp(Op op) {
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

​ 我们继续来看BackStackRecord#commit,最后调用了FragmentManagerImpl#enqueueAction

public int commit() {
    return commitInternal(false);
}

    int commitInternal(boolean allowStateLoss) {
        ……
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

​ FragmentManagerImpl#enqueueAction调用了FragmentManagerImpl#scheduleCommit();

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            if (allowStateLoss) {
                // This FragmentManager isn't attached, so drop the entire transaction.
                return;
            }
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<>();
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}

​ FragmentManagerImpl#scheduleCommit没有直接将Fragment添加到Fragment,而是发送了一个Runnable消息给主线程。

void scheduleCommit() {
    synchronized (this) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}

​ FragmentManagerImpl#mExecCommit调用了doPendingDeferredStart();等函数来创建Fragment。

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

public boolean execPendingActions() {
    ensureExecReady(true);

    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    updateOnBackPressedCallbackEnabled();
    doPendingDeferredStart();
    burpActive();

    return didSomething;
}

​ FragmentManagerImpl#doPendingDeferredStart 最终会调用FragmentManagerImpl#moveToState,在这里可以看到熟悉的Fragment生命周期了

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                 boolean keepActive) {
    // Fragments that are not currently added will sit in the onCreate() state.
    if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
        newState = Fragment.CREATED;
    }
    if (f.mRemoving && newState > f.mState) {
        if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
            // Allow the fragment to be created so that it can be saved later.
            newState = Fragment.CREATED;
        } else {
            // While removing a fragment, we can't change it to a higher state.
            newState = f.mState;
        }
    }
    // Defer start if requested; don't allow it to move to STARTED or higher
    // if it's not already started.
    if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.ACTIVITY_CREATED) {
        newState = Fragment.ACTIVITY_CREATED;
    }
    // Don't allow the Fragment to go above its max lifecycle state
    // Ensure that Fragments are capped at CREATED instead of ACTIVITY_CREATED.
    if (f.mMaxState == Lifecycle.State.CREATED) {
        newState = Math.min(newState, Fragment.CREATED);
    } else {
        newState = Math.min(newState, f.mMaxState.ordinal());
    }
    if (f.mState <= newState) {
        // For fragments that are created from a layout, when restoring from
        // state we don't want to allow them to be created until they are
        // being reloaded from the layout.
        if (f.mFromLayout && !f.mInLayout) {
            return;
        }
        if (f.getAnimatingAway() != null || f.getAnimator() != null) {
            // The fragment is currently being animated...  but!  Now we
            // want to move our state back up.  Give up on waiting for the
            // animation, move to whatever the final state should be once
            // the animation is done, and then we can proceed from there.
            f.setAnimatingAway(null);
            f.setAnimator(null);
            moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
        }
        switch (f.mState) {
            case Fragment.INITIALIZING:
            ……
                // fall through
            case Fragment.CREATED:
            ……
                // fall through
            case Fragment.ACTIVITY_CREATED:
            ……
                // fall through
            case Fragment.STARTED:
            ……
        }
    } else if (f.mState > newState) {
        switch (f.mState) {
            case Fragment.RESUMED:
            ……
                // fall through
            case Fragment.STARTED:
            ……
                // fall through
            case Fragment.ACTIVITY_CREATED:
            ……

            case Fragment.CREATED:
                ……
                
        }
    }

    if (f.mState != newState) {
        Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                + "expected state " + newState + " found " + f.mState);
        f.mState = newState;
    }
}

​ 综上所述,从beginTransaction()开始,我们获得了一个BackStackRecord对象,接着执行一系列对Fragment的操作,但最终是通过Handler发送Runnable给主线程来实际管理Fragment和Activity的联系。因为消息队列的执行时间和commit()函数执行完成的时间不是同步的,因此存在commit执行完成,而Fragment还没有创建完成的情况。

​ 也就是说commit之后,val homeFragment=supportFragmentManager.getFragment(Bundle(),"home")不一定能够立即获取到homeFragment。这一点使我们开发过程中需要注意和解决的。

参考文献:

[1] https://www.jianshu.com/p/9ecea420eb52

[2] https://www.jianshu.com/p/db198a499747

[3] https://www.jianshu.com/p/327f583f970b

[4] https://www.jianshu.com/p/388166988cef

[5] https://blog.csdn.net/start_mao/article/details/98963744

[6] https://blog.csdn.net/chengkun_123/article/details/72548373

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。