Dialog會影響Activity的生命周期祟身?

還記得剛學(xué)Android那會坡脐,經(jīng)常會說起Activity的七大生命周期:

onCreate,onRestart,onStart,onResume,onPause,onStop,onDestroy泄私。

  1. Activity啟動的時候會執(zhí)行onCreate->onStart->onResume
  2. Activity被遮擋,但是依然可見時會執(zhí)行onPause
  3. Activity不可見時,會執(zhí)行onStop
  4. Activity在即將關(guān)閉的情況下會執(zhí)行onDestroy方法挖滤。

所以會有相當(dāng)一部分的Android開發(fā)者相信在Dialog彈出的時候Activity會執(zhí)行onPause的生命周期(Dialog彈出的時候Activity確實被遮擋,并且是可見狀態(tài)),那么到底是不是這樣浅役,我們可以做個demo驗證一下這種case:

package com.netease.myapplication;

import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG,"onCreate");
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG,"onRestart");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG,"onStart");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG,"onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG,"onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG,"onStop");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG,"onDestroy");
    }

    public void showDialog(View view) {
        Dialog dialog = new Dialog(this);
        TextView textView = new TextView(this);
        textView.setText("這是一個彈窗");
        dialog.addContentView(textView,new ViewGroup.LayoutParams(200,200));
        dialog.show();
    }
}

首先是建了一個Activity斩松,在七大生命周期上面都打出log, 然后寫一個Button的click方法觉既,主要就是為了彈出Dialog惧盹。那我們先看Activity創(chuàng)建的生命周期:


QQ20210123-164309-HD.gif

很簡單的一個過程,生命周期如下:

2021-01-23 16:42:57.413 10039-10039/com.netease.myapplication I/MainActivity: onCreate
2021-01-23 16:42:57.615 10039-10039/com.netease.myapplication I/MainActivity: onStart
2021-01-23 16:42:57.617 10039-10039/com.netease.myapplication I/MainActivity: onResume

嗯瞪讼,預(yù)料之中的結(jié)果钧椰。接下來我們再彈出Dialog試試:

QQ20210123-164558-HD.gif

就只是簡單的彈出一個Dialog(無視如此丑的彈窗),然后再看下生命周期:


QQ20210123-164618@2x.png

發(fā)現(xiàn)Activity并沒有執(zhí)行任何的生命周期。既然不會調(diào)用生命周期符欠,那么以前聽說的彈出一個dialog會調(diào)用onPause的說法是從哪來的嫡霞?這個問題暫且不論,我們先來看下Dialog的過程:

        Dialog dialog = new Dialog(this);
        TextView textView = new TextView(this);
        textView.setText("這是一個彈窗");
        dialog.addContentView(textView,new ViewGroup.LayoutParams(200,200));
        dialog.show();

我們可以看到Dialog主要做了三步操作:

創(chuàng)建一個Dialog對象
將View通過addContentView添加進(jìn)去
顯示Dialog希柿。

1. 首先第一步诊沪,創(chuàng)建一個Dialog對象

    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == Resources.ID_NULL) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }
        //獲取WindowManagerService
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        //初始化Dialog的window
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        //給Window設(shè)置callback
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }

Dialog的構(gòu)造方法里面主要做了以下幾件事情:

  1. 創(chuàng)建Dialog的context
  2. 獲取WindowManagerImpl
  3. 初始化Dialog的window,設(shè)置callback曾撤,將WindowManagerImpl和Dialog的Window關(guān)聯(lián)起來(這里Dialog的window跟Activity的Window是不一致的端姚,所以在一旦Dialog彈出來的時候,觸摸事件就會被Dialog所在的Window所響應(yīng)挤悉,這里不做展開)
  4. 初始化ListenersHandler渐裸,Dialog的操作會通過這個Handler響應(yīng)。

2. Dialog的addContentView的操作:

    public void addContentView(@NonNull View view, @Nullable ViewGroup.LayoutParams params) {
        mWindow.addContentView(view, params);
    }

會通過Window將當(dāng)前的View add進(jìn)去装悲,PhoneWindow主要是初始化了DecorView昏鹃,然后通過DecorView獲取了里面的mContentParent控件,再將View添加到mContentParent里面衅斩。

3. Dialog的show過程

    public void show() {
        if (mShowing) {
            //做一個屏障盆顾,防止多次彈出彈窗
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;

        if (!mCreated) {
            dispatchOnCreate(null);
        } else {
            // Fill the DecorView in on any configuration changes that
            // may have occured while it was removed from the WindowManager.
            final Configuration config = mContext.getResources().getConfiguration();
            mWindow.getDecorView().dispatchConfigurationChanged(config);
        }

        //Dialog的onStart生命周期
        onStart();
        mDecor = mWindow.getDecorView();

        ...代碼省略...
        //將DecorView加入到WindowManagerImpl中
        mWindowManager.addView(mDecor, l);
        ...代碼省略...
        //發(fā)送Show的消息
        sendShowMessage();
    }

show操作主要是將DecorView添加到WindowManagerImpl里面,然后調(diào)用WindowManagerGlobal畏梆,會創(chuàng)建ViewRootImpl的對象您宪,最后執(zhí)行ViewRootImpl的performMeasure,performLayout和performDraw方法奠涌,最終會將Dialog展示到屏幕上面宪巨。而最后一步就是執(zhí)行onShow的回調(diào)方法。沒有其他額外操作

至此Dialog的顯示過程全部結(jié)束溜畅,流程比較簡單捏卓。我們發(fā)現(xiàn)這里面并沒有涉及到ActivityManagerService。另外對于Activty啟動流程熟悉的也知道Activity的生命周期必須通過ActivityManagerService來分配調(diào)用。所以Dialog的顯示自然不可能會影響Activity的生命周期怠晴。


既然如此遥金,那么為什么會有這種說法呢?這事先從Activity的跳轉(zhuǎn)到第二個Activity說起蒜田,關(guān)于Activity的具體啟動流程這里不再贅述稿械,在經(jīng)過一系列的方法調(diào)用以后,最終會調(diào)用ActivityStarter#startActivity方法冲粤,那么就從這個方法開始說起:

    private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
                ActivityRecord[] outActivity, boolean restrictedBgActivity) {
        int result = START_CANCELED;
        final ActivityStack startedActivityStack;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity, restrictedBgActivity);
        } finally {
            final ActivityStack currentStack = r.getActivityStack();
            startedActivityStack = currentStack != null ? currentStack : mTargetStack;

            if (ActivityManager.isStartResultSuccessful(result)) {
                if (startedActivityStack != null) {
                    // If there is no state change (e.g. a resumed activity is reparented to
                    // top of another display) to trigger a visibility/configuration checking,
                    // we have to update the configuration for changing to different display.
                    final ActivityRecord currentTop =
                            startedActivityStack.topRunningActivityLocked();
                    if (currentTop != null && currentTop.shouldUpdateConfigForDisplayChanged()) {
                        mRootActivityContainer.ensureVisibilityAndConfig(
                                currentTop, currentTop.getDisplayId(),
                                true /* markFrozenIfConfigChanged */, false /* deferResume */);
                    }
                }
            } else {
                ...代碼省略...
            }
            mService.mWindowManager.continueSurfaceLayout();
        }

        postStartActivityProcessing(r, result, startedActivityStack);

        return result;
    }

這個方法主要做了兩件事情:

啟動下一個Activity (startActivityUnchecked)
根據(jù)實際情況設(shè)置其他Activity的狀態(tài)是否為不可見 (mRootActivityContainer.ensureVisibilityAndConfig)

我們先來看下第一步操作startActivityUnchecked美莫,這個方法接下來會調(diào)用RootActivityContainer#resumeFocusedStacksTopActivities方法(RootActivityContainer是Android10以后新增的類),然后調(diào)用ActivityStack#resumeTopActivityUncheckedLocked->調(diào)用ActivityStack#resumeTopActivityInnerLocked方法:

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        ...代碼省略...
        boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }

        ...代碼省略...
        return true;
    }

這個方法非常的長梯捕,這里只需要關(guān)注startPausingLocked即可厢呵,這個方法首先會調(diào)用startPausingLocked方法pause掉當(dāng)前的Activity,然后后面會啟動下一個Activity傀顾。

    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean pauseImmediately) {
        ...代碼省略...

        if (prev.attachedToProcess()) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
            try {
                EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
                        prev.shortComponentName, "userLeaving=" + userLeaving);

                mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
                        prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                prev.configChangeFlags, pauseImmediately));
            } catch (Exception e) {
                // Ignore exception, if process died other code will cleanup.
                Slog.w(TAG, "Exception thrown during pause", e);
                mPausingActivity = null;
                mLastPausedActivity = null;
                mLastNoHistoryActivity = null;
            }
        } else {
            mPausingActivity = null;
            mLastPausedActivity = null;

            mLastNoHistoryActivity = null;
        }
        ...代碼省略...

    }

這段代碼就比較常見了襟铭,通過Android9.0 Activity啟動原理差異解析這篇文章可知,最終會指定PauseActivityItem的execute方法锣笨,然后執(zhí)行對應(yīng)的postExecute方法蝌矛。當(dāng)然這里采用的是Binder機制進(jìn)行調(diào)用,屬于異步的調(diào)用错英,但是result會直接返回入撒,正常情況下result都會是true。那么start結(jié)束以后椭岩,在回過頭看剛才說的RootActivityContainer#ensureVisibilityAndConfig方法,下面給出調(diào)用鏈

RootActivityContainer#ensureActivitiesVisible
ActivityDisplay#ensureActivitiesVisible
ActivityStack#ensureActivitiesVisibleLocked

    final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows, boolean notifyClients) {
            ...代碼省略...
            // If the top activity is not fullscreen, then we need to
            // make sure any activities under it are now visible.
            boolean aboveTop = top != null;
            final boolean stackShouldBeVisible = shouldBeVisible(starting);
            boolean behindFullscreenActivity = !stackShouldBeVisible;
            boolean resumeNextActivity = isFocusable() && isInStackLocked(starting) == null;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                final TaskRecord task = mTaskHistory.get(taskNdx);
                final ArrayList<ActivityRecord> activities = task.mActivities;
                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                    final ActivityRecord r = activities.get(activityNdx);
                    if (r.finishing) {
                        continue;
                    }
                    final boolean isTop = r == top;
                    if (aboveTop && !isTop) {
                        continue;
                    }
                    aboveTop = false;

                    // Check whether activity should be visible without Keyguard influence
                    final boolean visibleIgnoringKeyguard = r.shouldBeVisibleIgnoringKeyguard(
                            behindFullscreenActivity);
                    final boolean reallyVisible = r.shouldBeVisible(behindFullscreenActivity);
                    if (visibleIgnoringKeyguard) {
                        behindFullscreenActivity = updateBehindFullscreen(!stackShouldBeVisible,
                                behindFullscreenActivity, r);
                    }
                    if (reallyVisible) {
                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
                                + " finishing=" + r.finishing + " state=" + r.getState());
                        // First: if this is not the current activity being started, make
                        // sure it matches the current configuration.
                        if (r != starting && notifyClients) {
                            r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
                                    true /* ignoreStopState */);
                        }

                        if (!r.attachedToProcess()) {
                            if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
                                    resumeNextActivity, r)) {
                                if (activityNdx >= activities.size()) {
                                    // Record may be removed if its process needs to restart.
                                    activityNdx = activities.size() - 1;
                                } else {
                                    resumeNextActivity = false;
                                }
                            }
                        } else if (r.visible) {
                            // If this activity is already visible, then there is nothing to do here.
                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                    "Skipping: already visible at " + r);

                            if (r.mClientVisibilityDeferred && notifyClients) {
                                r.makeClientVisible();
                            }

                            if (r.handleAlreadyVisible()) {
                                resumeNextActivity = false;
                            }

                            if (notifyClients) {
                                r.makeActiveIfNeeded(starting);
                            }
                        } else {
                            r.makeVisibleIfNeeded(starting, notifyClients);
                        }
                        // Aggregate current change flags.
                        configChanges |= r.configChangeFlags;
                    } else {
                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r
                                + " finishing=" + r.finishing + " state=" + r.getState()
                                + " stackShouldBeVisible=" + stackShouldBeVisible
                                + " behindFullscreenActivity=" + behindFullscreenActivity
                                + " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
                        makeInvisible(r);
                    }
                }
            ...代碼省略...
    }

看代碼注釋茅逮,當(dāng)top Activity不是全屏Activity的時候,我們需要保證任何在這個非全屏Activity下面的Activity都是visible狀態(tài)判哥,所以對應(yīng)的ActivityRecord的visible為true献雅,那么什么作用呢?下面接著看客戶端這邊PauseActivityItem的postExecute方法

    @Override
    public void postExecute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        if (mDontReport) {
            return;
        }
        try {
            // TODO(lifecycler): Use interface callback instead of AMS.
            ActivityTaskManager.getService().activityPaused(token);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

execute方法就是將客戶端的Activity狀態(tài)設(shè)置成onPause塌计,而postExecute方法就是將服務(wù)端對應(yīng)的ActivityRecord的狀態(tài)設(shè)置成pause挺身。然后通過AMS調(diào)用到ActivityStack#activityPausedLocked方法:

    final void activityPausedLocked(IBinder token, boolean timeout) {
        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
            "Activity paused: token=" + token + ", timeout=" + timeout);

        final ActivityRecord r = isInStackLocked(token);

        if (r != null) {
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
                if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + r
                        + (timeout ? " (due to timeout)" : " (pause complete)"));
                mService.mWindowManager.deferSurfaceLayout();
                try {
                    completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
                } finally {
                    mService.mWindowManager.continueSurfaceLayout();
                }
                return;
            } else {
                EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                        r.mUserId, System.identityHashCode(r), r.shortComponentName,
                        mPausingActivity != null
                            ? mPausingActivity.shortComponentName : "(none)");
                if (r.isState(PAUSING)) {
                    r.setState(PAUSED, "activityPausedLocked");
                    if (r.finishing) {
                        if (DEBUG_PAUSE) Slog.v(TAG,
                                "Executing finish of failed to pause activity: " + r);
                        finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false,
                                "activityPausedLocked");
                    }
                }
            }
        }
        mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
    }

上面這段代碼執(zhí)行完畢以后,服務(wù)端的對應(yīng)的ActivityRecord也正是進(jìn)入了pause狀態(tài)锌仅,然后最頂上的Activity正式啟動章钾,會一次調(diào)用onCreate,onStart热芹,onResume贱傀。根據(jù)這篇文章可知,當(dāng)ActivityThread調(diào)用handleResumeActivity的時候伊脓,在最后會add一個IdleHandler用來stop上一個已經(jīng)處于pause狀態(tài)的Activity府寒。下面給出調(diào)用鏈:

ActivityTaskManagerService#activityIdle
ActivityStackSuperVisor#activityIdleInternalLocked

    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
            boolean processPausingActivities, Configuration config) {
        ...代碼省略...
       

        // Atomically retrieve all of the other things to do.
        final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
                true /* remove */, processPausingActivities);
        NS = stops != null ? stops.size() : 0;
        if ((NF = mFinishingActivities.size()) > 0) {
            finishes = new ArrayList<>(mFinishingActivities);
            mFinishingActivities.clear();
        }

        if (mStartingUsers.size() > 0) {
            startingUsers = new ArrayList<>(mStartingUsers);
            mStartingUsers.clear();
        }

        // Stop any activities that are scheduled to do so but have been
        // waiting for the next one to start.
        for (int i = 0; i < NS; i++) {
            r = stops.get(i);
            final ActivityStack stack = r.getActivityStack();
            if (stack != null) {
                if (r.finishing) {
                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
                            "activityIdleInternalLocked");
                } else {
                    stack.stopActivityLocked(r);
                }
            }
        }

        ...代碼省略...

        return r;
    }

這里會獲取對應(yīng)的stops列表,然后對列表中的所有ActivityRecord進(jìn)行判斷,如果finishing狀態(tài)是true的那么執(zhí)行finish操作株搔,如果是false的就執(zhí)行stop操作剖淀。那么我們再來看下stops列表是如何獲取的

final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
                true /* remove */, processPausingActivities);

調(diào)用的processStoppingActivitiesLocked方法獲取的,最終是從mStoppingActivities里面獲取的纤房。那么mStoppingActivities什么時候會把ActivityRecord add進(jìn)來呢祷蝌?搜索了一下這個對象的使用地方:


image.png

發(fā)現(xiàn)只有一處地方有add操作,那么點過去看下代碼:

    private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed,
            String reason) {
        if (!mStackSupervisor.mStoppingActivities.contains(r)) {
            EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, r.mUserId,
                    System.identityHashCode(r), r.shortComponentName, reason);
            mStackSupervisor.mStoppingActivities.add(r);
        }

        // If we already have a few activities waiting to stop, then give up
        // on things going idle and start clearing them out. Or if r is the
        // last of activity of the last task the stack will be empty and must
        // be cleared immediately.
        boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
                || (r.frontOfTask && mTaskHistory.size() <= 1);
        if (scheduleIdle || forceIdle) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle="
                    + forceIdle + "immediate=" + !idleDelayed);
            if (!idleDelayed) {
                mStackSupervisor.scheduleIdleLocked();
            } else {
                mStackSupervisor.scheduleIdleTimeoutLocked(r);
            }
        } else {
            checkReadyForSleep();
        }
    }

這個方法判斷當(dāng)前mStoppingActivities列表里面是否包含指定的ActivityRecord帆卓,如果不包含那就添加進(jìn)來,很明顯了只要執(zhí)行了這段代碼米丘,那么mStoppingActivities肯定就會添加這個ActivityRecord剑令,然后必然會在前面ActivityStackSuperVisor#activityIdleInternalLocked的方法中執(zhí)行對應(yīng)的stop方法。那么接下來就看什么時候這個addToStopping執(zhí)行了拄查。我們可以發(fā)現(xiàn)下面這個方法:

   private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
        ...代碼省略吁津。。堕扶。

        if (prev != null) {
            prev.setWillCloseOrEnterPip(false);
            final boolean wasStopping = prev.isState(STOPPING);
            prev.setState(PAUSED, "completePausedLocked");
            if (prev.finishing) {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
                        "completePausedLocked");
            } else if (prev.hasProcess()) {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                        + " wasStopping=" + wasStopping + " visible=" + prev.visible);
                if (prev.deferRelaunchUntilPaused) {
                    // Complete the deferred relaunch that was waiting for pause to complete.
                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
                    prev.relaunchActivityLocked(false /* andResume */,
                            prev.preserveWindowOnDeferredRelaunch);
                } else if (wasStopping) {
                    // We are also stopping, the stop request must have gone soon after the pause.
                    // We can't clobber it, because the stop confirmation will not be handled.
                    // We don't need to schedule another stop, we only need to let it happen.
                    prev.setState(STOPPING, "completePausedLocked");
                } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
                    // Clear out any deferred client hide we might currently have.
                    prev.setDeferHidingClient(false);
                    // If we were visible then resumeTopActivities will release resources before
                    // stopping.
                    addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */,
                            "completePauseLocked");
                }
            } else {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
                prev = null;
            }
            // It is possible the activity was freezing the screen before it was paused.
            // In that case go ahead and remove the freeze this activity has on the screen
            // since it is no longer visible.
            if (prev != null) {
                prev.stopFreezingScreenLocked(true /*force*/);
            }
            mPausingActivity = null;
        }


        ...代碼省略...
    }
  1. 首先prev并沒有調(diào)用finish方法碍脏, 所以finishing狀態(tài)肯定是false。
  2. 然后根據(jù)淺談APP的回收和重啟機制可知稍算,只有在系統(tǒng)回收當(dāng)前Activity的時候
    prev.hasProcess()才會是false典尾, 所以正常情況下這個值必然是true。
  3. prev并沒有重新啟動糊探,當(dāng)前狀態(tài)也不是stopping钾埂,所以就看最后一個判斷邏輯。
  4. shouldSleepOrShutDownActivities()方法判斷當(dāng)前手機是否關(guān)機或者鎖屏科平,很明顯這里的判斷是false
  5. 而一旦將要啟動的Activity是非全屏的Activity的時候褥紫,prev.visible會是true,所以(!prev.visible || shouldSleepOrShutDownActivities())這個條件不滿足瞪慧,也就是不會指定addToStopping方法髓考,那么根據(jù)上面的結(jié)論,prev對應(yīng)的Activity也就不會執(zhí)行onStop方法了弃酌。

總結(jié)

所以Dialog彈出時是不會影響Activity生命周期的氨菇,Activity也就不會進(jìn)入所謂的onPause狀態(tài)。所謂的可見狀態(tài)下進(jìn)入onPause其實說的是透明背景的Activity或者是Dialog主題的Activity彈出來的時候矢腻,那么前一個頁面確實只會調(diào)用onPause方法门驾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市多柑,隨后出現(xiàn)的幾起案子奶是,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聂沙,死亡現(xiàn)場離奇詭異秆麸,居然都是意外死亡,警方通過查閱死者的電腦和手機及汉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門沮趣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坷随,你說我怎么就攤上這事房铭。” “怎么了温眉?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵缸匪,是天一觀的道長虾攻。 經(jīng)常有香客問我糙及,道長,這世上最難降的妖魔是什么衫嵌? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任闯冷,我火速辦了婚禮砂心,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛇耀。我一直安慰自己辩诞,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布纺涤。 她就那樣靜靜地躺著躁倒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洒琢。 梳的紋絲不亂的頭發(fā)上秧秉,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音衰抑,去河邊找鬼象迎。 笑死,一個胖子當(dāng)著我的面吹牛呛踊,可吹牛的內(nèi)容都是我干的砾淌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼谭网,長吁一口氣:“原來是場噩夢啊……” “哼汪厨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起愉择,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤劫乱,失蹤者是張志新(化名)和其女友劉穎织中,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷戈,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡狭吼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了殖妇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刁笙。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谦趣,靈堂內(nèi)的尸體忽然破棺而出疲吸,到底是詐尸還是另有隱情,我是刑警寧澤前鹅,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布磅氨,位于F島的核電站,受9級特大地震影響嫡纠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜延赌,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一除盏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挫以,春花似錦者蠕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至大磺,卻和暖如春抡句,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杠愧。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工待榔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人流济。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓锐锣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绳瘟。 傳聞我的和親對象是個殘疾皇子雕憔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容