Dialog会影响Activity的生命周期?

还记得刚学Android那会,经常会说起Activity的七大生命周期:

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

  1. Activity启动的时候会执行onCreate->onStart->onResume
  2. Activity被遮挡,但是依然可见时会执行onPause
  3. Activity不可见时,会执行onStop
  4. Activity在即将关闭的情况下会执行onDestroy方法。

所以会有相当一部分的Android开发者相信在Dialog弹出的时候Activity会执行onPause的生命周期(Dialog弹出的时候Activity确实被遮挡,并且是可见状态),那么到底是不是这样,我们可以做个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创建的生命周期:


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

嗯,预料之中的结果。接下来我们再弹出Dialog试试:

QQ20210123-164558-HD.gif

就只是简单的弹出一个Dialog(无视如此丑的弹窗),然后再看下生命周期:


QQ20210123-164618@2x.png

发现Activity并没有执行任何的生命周期。既然不会调用生命周期,那么以前听说的弹出一个dialog会调用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主要做了三步操作:

创建一个Dialog对象
将View通过addContentView添加进去
显示Dialog。

1. 首先第一步,创建一个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设置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的构造方法里面主要做了以下几件事情:

  1. 创建Dialog的context
  2. 获取WindowManagerImpl
  3. 初始化Dialog的window,设置callback,将WindowManagerImpl和Dialog的Window关联起来(这里Dialog的window跟Activity的Window是不一致的,所以在一旦Dialog弹出来的时候,触摸事件就会被Dialog所在的Window所响应,这里不做展开)
  4. 初始化ListenersHandler,Dialog的操作会通过这个Handler响应。

2. Dialog的addContentView的操作:

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

会通过Window将当前的View add进去,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);
        ...代码省略...
        //发送Show的消息
        sendShowMessage();
    }

show操作主要是将DecorView添加到WindowManagerImpl里面,然后调用WindowManagerGlobal,会创建ViewRootImpl的对象,最后执行ViewRootImpl的performMeasure,performLayout和performDraw方法,最终会将Dialog展示到屏幕上面。而最后一步就是执行onShow的回调方法。没有其他额外操作

至此Dialog的显示过程全部结束,流程比较简单。我们发现这里面并没有涉及到ActivityManagerService。另外对于Activty启动流程熟悉的也知道Activity的生命周期必须通过ActivityManagerService来分配调用。所以Dialog的显示自然不可能会影响Activity的生命周期。


既然如此,那么为什么会有这种说法呢?这事先从Activity的跳转到第二个Activity说起,关于Activity的具体启动流程这里不再赘述,在经过一系列的方法调用以后,最终会调用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)
根据实际情况设置其他Activity的状态是否为不可见 (mRootActivityContainer.ensureVisibilityAndConfig)

我们先来看下第一步操作startActivityUnchecked,这个方法接下来会调用RootActivityContainer#resumeFocusedStacksTopActivities方法(RootActivityContainer是Android10以后新增的类),然后调用ActivityStack#resumeTopActivityUncheckedLocked->调用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;
    }

这个方法非常的长,这里只需要关注startPausingLocked即可,这个方法首先会调用startPausingLocked方法pause掉当前的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方法,然后执行对应的postExecute方法。当然这里采用的是Binder机制进行调用,属于异步的调用,但是result会直接返回,正常情况下result都会是true。那么start结束以后,在回过头看刚才说的RootActivityContainer#ensureVisibilityAndConfig方法,下面给出调用链

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);
                    }
                }
            ...代码省略...
    }

看代码注释,当top Activity不是全屏Activity的时候,我们需要保证任何在这个非全屏Activity下面的Activity都是visible状态,所以对应的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状态设置成onPause,而postExecute方法就是将服务端对应的ActivityRecord的状态设置成pause。然后通过AMS调用到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);
    }

上面这段代码执行完毕以后,服务端的对应的ActivityRecord也正是进入了pause状态,然后最顶上的Activity正式启动,会一次调用onCreate,onStart,onResume。根据这篇文章可知,当ActivityThread调用handleResumeActivity的时候,在最后会add一个IdleHandler用来stop上一个已经处于pause状态的Activity。下面给出调用链:

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

这里会获取对应的stops列表,然后对列表中的所有ActivityRecord进行判断,如果finishing状态是true的那么执行finish操作,如果是false的就执行stop操作。那么我们再来看下stops列表是如何获取的

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

调用的processStoppingActivitiesLocked方法获取的,最终是从mStoppingActivities里面获取的。那么mStoppingActivities什么时候会把ActivityRecord add进来呢?搜索了一下这个对象的使用地方:


image.png

发现只有一处地方有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();
        }
    }

这个方法判断当前mStoppingActivities列表里面是否包含指定的ActivityRecord,如果不包含那就添加进来,很明显了只要执行了这段代码,那么mStoppingActivities肯定就会添加这个ActivityRecord,然后必然会在前面ActivityStackSuperVisor#activityIdleInternalLocked的方法中执行对应的stop方法。那么接下来就看什么时候这个addToStopping执行了。我们可以发现下面这个方法:

   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并没有调用finish方法, 所以finishing状态肯定是false。
  2. 然后根据浅谈APP的回收和重启机制可知,只有在系统回收当前Activity的时候
    prev.hasProcess()才会是false, 所以正常情况下这个值必然是true。
  3. prev并没有重新启动,当前状态也不是stopping,所以就看最后一个判断逻辑。
  4. shouldSleepOrShutDownActivities()方法判断当前手机是否关机或者锁屏,很明显这里的判断是false
  5. 而一旦将要启动的Activity是非全屏的Activity的时候,prev.visible会是true,所以(!prev.visible || shouldSleepOrShutDownActivities())这个条件不满足,也就是不会指定addToStopping方法,那么根据上面的结论,prev对应的Activity也就不会执行onStop方法了。

总结

所以Dialog弹出时是不会影响Activity生命周期的,Activity也就不会进入所谓的onPause状态。所谓的可见状态下进入onPause其实说的是透明背景的Activity或者是Dialog主题的Activity弹出来的时候,那么前一个页面确实只会调用onPause方法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,271评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,725评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,252评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,634评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,549评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,985评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,471评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,128评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,257评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,233评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,235评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,940评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,528评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,623评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,858评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,245评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,790评论 2 339

推荐阅读更多精彩内容