從源碼角度看finish()方法的執行流程


1. finish()方法概覽

    首先我們來看一下finish方法的無參版本的定義:

/**
 * Call this when your activity is done and should be closed.  The
 * ActivityResult is propagated back to whoever launched you via
 * onActivityResult(). */
public void finish() {
    finish(false);
}

 

    根據源碼中的注釋我們可以知道,當我們的activity已經完成它的工作,我們想要關閉它時,我們可以調用finish()方法。這個方法內部回去調用finish(boolean)方法,並傳入false作為參數。那么接下來我們從finish(boolean)方法出發,來了解下finish()方法的大致執行流程。

 

2. finish()方法執行流程

 1     /**
 2      * Finishes the current activity and specifies whether to remove the task associated with this
 3      * activity.
 4      */
 5     private void finish(boolean finishTask) {
 6         if (mParent == null) {
 7             int resultCode;
 8             Intent resultData;
 9             synchronized (this) {
10                 resultCode = mResultCode;
11                 resultData = mResultData;
12             }
13             if (false) Log.v(TAG, "Finishing self: token=" + mToken);
14             try {
15                 if (resultData != null) {
16                     resultData.prepareToLeaveProcess();
17                 }
18                 if (ActivityManagerNative.getDefault()
19                         .finishActivity(mToken, resultCode, resultData, finishTask)) {
20                     mFinished = true;
21                 }
22             } catch (RemoteException e) {
23                 // Empty
24             }
25         } else {
26             mParent.finishFromChild(this);
27         }
28     }

     根據注釋我們可以知道boolean類型參數finishTask的作用是是否移除與我們要關閉的activity相關聯的task。我們注意到這個方法的訪問修飾符是private,所以它只是供Activity類內部調用的方法。那么我們接下來看一下這個方法究竟是怎樣實現關閉一個activity的。在第6行,我們判斷mParent是否為null。現在我們只需要知道mParent在一般情況下均為null即可。所以這個方法接下來會執行第7到24行的代碼。在第10行和第11行,我們分別把resultCode和resultData賦值為mResultCode和mResultData。resultCode和resultData最終會傳入到onActivityResult方法中。

    以上代碼的關鍵在於第18行調用的finishActivity方法,若這個方法返回true,我們就會設置Activity的mFinished成員變量為true。isFinishing()方法用於判斷一個Activity是否處於銷毀狀態,這個方法的實現就是返回mFinished成員變量。也就是說,若finishActivity方法執行完畢並返回true,則Activity就被成功銷毀了。下面我們回到第18行:通過調用ActivityManagerNative.getDefault()方法會得到一個ActivityManagerProxy對象,這是ActivityManagerService(下文簡稱為AMS)的代理對象。那么AMS是什么呢?這里我們只需要知道它是一個系統服務,系統中四大組件的啟動、切換、銷毀等都是由它負責的。我們通過ActivityManagerProxy對象可以請求AMS去啟動、暫停或是銷毀一個Activity。ActivityManagerProxy是ActivityManagerNative的一個內部類,它的finishActivity方法如下所示:

 1     public boolean finishActivity(IBinder token, int resultCode, Intent resultData, boolean finishTask)
 2             throws RemoteException {
 3         Parcel data = Parcel.obtain();
 4         Parcel reply = Parcel.obtain();
 5         data.writeInterfaceToken(IActivityManager.descriptor);
 6         data.writeStrongBinder(token);
 7         data.writeInt(resultCode);
 8         if (resultData != null) {
 9             data.writeInt(1);
10             resultData.writeToParcel(data, 0);
11         } else {
12             data.writeInt(0);
13         }
14         data.writeInt(finishTask ? 1 : 0);
15         mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
16         reply.readException();
17         boolean res = reply.readInt() != 0;
18         data.recycle();
19         reply.recycle();
20         return res;
21     }

 

 

    以上代碼中的reply用於保存返回結果,data會作為參數傳遞給AMS。我們首先向要傳遞給AMS的data中寫入了token、resultCode。若resultData不為null,則會先寫入一個整數1,再寫入resultData,若resultData為null,則只寫入一個整數0。然后我們再根據finishTask參數為true或false分別寫入1或0。以上代碼的關鍵在於第15行調用的mRemote.transact(...)方法,它會導致AMS的onTransact(...)方法被調用。AMS的onTransact方法調用了ActivityManagerNative的onTransact方法,這個方法的代碼如下:

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        ...
        case FINISH_ACTIVITY_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder token = data.readStrongBinder();
            Intent resultData = null;
            int resultCode = data.readInt();
            if (data.readInt() != 0) {
                resultData = Intent.CREATOR.createFromParcel(data);
            }
            boolean finishTask = (data.readInt() != 0);
            boolean res = finishActivity(token, resultCode, resultData, finishTask);
            reply.writeNoException();
            reply.writeInt(res ? 1 : 0);
            return true;
        }
        ...
    }

 

 

    我們可以看到,這個方法會根據傳入的code參數執行不同的case分支,這里會執行的是code為FINISH_ACTIVITY_TRANSACTION的分支。以上代碼中又調用了finishActivity方法(AMS中),所以我們接着看這個方法的實現:

 1     /**
 2      * This is the internal entry point for handling Activity.finish().
 3      * 
 4      * @param token The Binder token referencing the Activity we want to finish.
 5      * @param resultCode Result code, if any, from this Activity.
 6      * @param resultData Result data (Intent), if any, from this Activity.
 7      * 
 8      * @return Returns true if the activity successfully finished, or false if it is still running.
 9      */
10     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
11         // Refuse possible leaked file descriptors
12         if (resultData != null && resultData.hasFileDescriptors() == true) {
13             throw new IllegalArgumentException("File descriptors passed in Intent");
14         }
15         synchronized(this) {
16             ...33             final long origId = Binder.clearCallingIdentity();
17             boolean res = requestFinishActivityLocked(token, resultCode,
18                     resultData, "app-request");
19             Binder.restoreCallingIdentity(origId);
20             return res;
21         }
22     }

    根據源碼中的注釋我們可以看到,這個方法是處理Activity.finish()的內部入口點。這個方法內部又調用了requestFinishActivityLocked方法,所以我們還要接着跟進。requestFinishActivityLocked方法的源碼如下:

 1     private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
 2             Intent resultData, String reason) {
 3          ...
 4          HistoryRecord r = (HistoryRecord)mHistory.get(index);
 5          // Is this the last activity left?
 6          boolean lastActivity = true;
 7          for (int i=mHistory.size()-1; i>=0; i--) {
 8              HistoryRecord p = (HistoryRecord)mHistory.get(i);
 9              if (!p.finishing && p != r) {
10                  lastActivity = false;
11                  break;
12              }
13          }
14          
15          // If this is the last activity, but it is the home activity, then
16          // just don't finish it.
17          if (lastActivity) {
18             if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
19                  return false;
20             }
21          }
22          
23          finishActivityLocked(r, index, resultCode, resultData, reason);
24          return true;
25      }

 

 

 

    首先我們看一下第4行出現了HistoryRecord和mHistory。這里我們簡單的介紹一下它們兩個。mHistory是AMS的成員變量,它是一個ArrayList,里面存儲的元素類型為HistoryRecord,一個HistoryReord表示一個Activity。也就是說mHistory存儲了系統中所有曾經存在過或正在運行的Activity。第6行到第13行的功能就是判斷現在系統中是否只剩下一個正在運行Activity,這一點從注釋中就可以看出。然后在第17行到第21行,若唯一正在運行的Activity是HomeActivity,則直接返回false(不會關閉它)。以上代碼中的關鍵在於第23行調用的finishActivityLocked方法,這個方法的核心代碼如下:

    private final boolean finishActivityLocked(HistoryRecord r, int index,
            int resultCode, Intent resultData, String reason) {
        
        ...if (mResumedActivity == r) {
            ...
        } 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, "Finish not pausing: " + r);
            return finishCurrentActivityLocked(r, index,
                    FINISH_AFTER_PAUSE) == null;
        } else {
            if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
        }
        return false;
    }

 

    以上代碼實際上會調用finishCurrentActivityLocked方法,若這個方法返回值為null,finishActivityLocked則會返回true,否則會返回false。那么我們來看看finishCurrentActivityLocked方法的實現:

    private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
            int index, int mode) {
        ...

final ActivityState prevState = r.state; r.state = ActivityState.FINISHING; if (mode == FINISH_IMMEDIATELY || prevState == ActivityState.STOPPED || prevState == ActivityState.INITIALIZING) { // If this activity is already stopped, we can just finish // it right now. return destroyActivityLocked(r, true) ? null : r; } else { // Need to go through the full pause cycle to get this // activity into the stopped state and then finish it. if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r); mFinishingActivities.add(r); resumeTopActivityLocked(null); } return r; }

 

    根據源碼中的注釋我們可以知道,若Activity已經處於停止狀態,則可以立即調用destroyActivityLocked方法;否則我們需要先經歷完整的“暫停周期”以讓這個Activity處於停止狀態后再結束它。

   在destroyActivityLocked方法中存在如下這句代碼:

r.app.thread.scheduleDestroyActivity(r, r.finishing,r.configChangeFlags);

 

    其中,r.app.thread實際上是AMS持有的應用程序進程的ApplicationThread的代理對象,所以實際上調用的是ApplicationThread的scheduleDestroyActivity方法,而后這個方法中會向主線程(ActivityThread)發送一個H.DESTROY_ACTIVITY消息,主線程會調用handleDestroyActivity來處理這個消息,再經過層層調用后,Activity的onDestroy方法會被回調。對這一過程感興趣的同學可以自行閱讀相關源碼。

 

3. finish()方法總結

    通過上面對源碼的分析,我們大概了解了finish()方法的工作流程,有兩點需要我們注意:

(1)經過層層調用,ApplicationThread.scheduleDestroyActivity方法會被調用,這個方法會完成對Activity的銷毀工作,並且會回調Activity.onDestroy()方法。所以我們知道了調用finish()方法會導致對Acitivity的銷毀,從而導致Activity.onDestroy()被回調。

(2)在我們的日常開發中,往往會將finish()方法的調用包含在Activity的某個生命周期中,而實際上Activity的各個生命周期方法都是由ApplicationThread.scheduleXXXActivity方法回調的,這個方法會向主線程發送一個H.XXX_ACTIVITY消息,隨后主線程的Looper會從消息隊列中這個消息並調用handleXXXActivity方法來處理它,並最終會回到Activity.onXXX方法。比如我們在onCreate()方法中調用了finish()方法,那么由於此時主線程正處於對H.CREATE_ACTIVITY消息的處理中,所以暫時無法處理H.DESTROY_ACTIVITY消息,只有當主線程處理完前一個消息了,才會着手處理H_DESTROY_ACTIVITY消息。因此,我們調用finish()方法后,onDestroy()往往並不會被立即調用,但是我們可以通過isFinishing()方法來判斷Activity是否處於銷毀狀態。

 

    以上是我對finish()方法相關源碼的執行流程的總結,由於個人水平有限,敘述中難免存在不准確或是不清晰的地方,希望大家可以指出,謝謝大家:)

4. 參考資料

    https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r26/core/java/android/app

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM