Android进阶之旅Android开发Android开发经验谈

android 退出Activity源码分析

2017-02-28  本文已影响629人  super_shanks


我们首先知道退出应用是从最后的一个activity的finish方法开始的。

/**
     * Finishes the current activity and specifies whether to remove the task associated with this
     * activity.
     */
    private void finish(int finishTask) {
        if (mParent == null) {
            int resultCode;
            Intent resultData;
            synchronized (this) {
                resultCode = mResultCode;
                resultData = mResultData;
            }
            if (false) Log.v(TAG, "Finishing self: token=" + mToken);
            try {
                if (resultData != null) {
                    resultData.prepareToLeaveProcess(this);
                }
                if (ActivityManagerNative.getDefault()
                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
                    mFinished = true;
                }
            } catch (RemoteException e) {
                // Empty
            }
        } else {
            mParent.finishFromChild(this);
        }
    }

很显然,最主要的方法是ActivityManagerNative.getDefault().finishActivity(mToken, resultCode, resultData, finishTask),那么我们就来看AMS的finishActivity做了什么?:

else {
    res = tr.stack.requestFinishActivityLocked(token, resultCode,
            resultData, "app-request", true);
    if (!res) {
        Slog.i(TAG, "Failed to finish by app-request");
    }
}

代码比较长,最主要的就是上面的这一段,紧接着我们可以进入到finishActivityLocked方法:

/**
 * @return Returns true if this activity has been removed from the history
 * list, or false if it is still in the list and will be removed later.
 */
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
        String reason, boolean oomAdj) {
    ...
    if (mResumedActivity == r) {

        if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                "Prepare close transition: finishing " + r);
        mWindowManager.prepareAppTransition(transit, false);

        // Tell window manager to prepare for this one to be removed.
        mWindowManager.setAppVisibility(r.appToken, false);

        if (mPausingActivity == null) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                    "finish() => pause with userLeaving=false");
            startPausingLocked(false, false, null, false);
        }

        if (endTask) {
            mStackSupervisor.removeLockedTaskLocked(task);
        }
    } else if (r.state != ActivityState.PAUSING) {
        // If the activity is PAUSING, we will complete the finish once
        // it is done pausing; else we can just directly finish it here.
        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
        if (r.visible) {
            mWindowManager.prepareAppTransition(transit, false);
            mWindowManager.setAppVisibility(r.appToken, false);
            mWindowManager.executeAppTransition();
            if (!mStackSupervisor.mWaitingVisibleActivities.contains(r)) {
                mStackSupervisor.mWaitingVisibleActivities.add(r);
            }
        }
        return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
                FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
    } else {
        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
    }

    return false;
}

主要是两个方法,startPausingLocked和finishCurrentActivityLocked,我们先看前者:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
            ActivityRecord resuming, boolean dontWait) {
        ...

        if (prev.app != null && prev.app.thread != null) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
            try {
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        prev.userId, System.identityHashCode(prev),
                        prev.shortComponentName);
                mService.updateUsageStats(prev, false);
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            } 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;
        }

        ...
    }

我们可以看到,由于是AMS发起的方法,那么可能是跨进程的调用,那么就直接调用ActivityRecord.app.thread去调用applicationThread的schedulePauseActivity方法(这个ApplicationThread是ActivityThread的内部类,也是binder的东西),然后我们知道在schedulePauseActivity方法就会去执行activity的pause操作,并且回调onPause方法,一路追溯,来到handlePauseActivity方法:

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
        ActivityClientRecord r = mActivities.get(token);
        if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
        if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
            return;
        }
        if (r != null) {
            //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
            if (userLeaving) {
                performUserLeavingActivity(r);
            }

            r.activity.mConfigChangeFlags |= configChanges;
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");

            // Make sure any pending writes are now committed.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }

            // Tell the activity manager we have paused.
            if (!dontReport) {
                try {
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }

其中performPauseActivity方法就是去pause并且回调onPause的,另外一个就是ActivityManagerNative.getDefault().activityPaused(token)去调AMS服务的activityPaused方法,一路看下去,最后终归会去调用finishCurrentActivityLocked方法,就是最最前面我们需要分析的第二个方法了:

final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
        ...

        if (mode == FINISH_IMMEDIATELY
                || (prevState == ActivityState.PAUSED
                    && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID))
                || finishingActivityInNonFocusedStack
                || prevState == ActivityState.STOPPED
                || prevState == ActivityState.INITIALIZING) {
            r.makeFinishingLocked();
            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");

            if (finishingActivityInNonFocusedStack) {
                // Finishing activity that was in paused state and it was in not currently focused
                // stack, need to make something visible in its place.
                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
            }
            if (activityRemoved) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
            }
            if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                    "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
                    " destroy returned removed=" + activityRemoved);
            return activityRemoved ? null : r;
        }
        ...
    }

重要的就是这个destroyActivityLocked方法,继续看:

final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
        ...
            try {
                if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
                r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
                        r.configChangeFlags);
            } catch (Exception e) {
                // We can just ignore exceptions here...  if the process
                // has crashed, our death notification will clean things
                // up.
                //Slog.w(TAG, "Exception thrown during finish", e);
                if (r.finishing) {
                    removeActivityFromHistoryLocked(
                            r, topTask, reason + " exceptionInScheduleDestroy");
                    removedFromHistory = true;
                    skipDestroy = true;
                }
            }

            ...
    }

scheduleDestroyActivity方法,好了吧,一目了然了吧。但是看到这里也许有的人会问,怎么没有stop方法,这里我们在深入一下,你可以顺这再去看,在performDestoryActivity方法中,我们可以找到这样一段:

if (!r.stopped) {
    try {
        r.activity.performStop(r.mPreserveWindow);
    } catch (SuperNotCalledException e) {
        throw e;
    } catch (Exception e) {
        if (!mInstrumentation.onException(r.activity, e)) {
            throw new RuntimeException(
                    "Unable to stop activity "
                    + safeToComponentShortString(r.intent)
                    + ": " + e.toString(), e);
        }
    }
    r.stopped = true;
    EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
            r.activity.getComponentName().getClassName(), "destroy");
}
上一篇 下一篇

猜你喜欢

热点阅读