Activity 的 isFinishing()、isDestroy()

結論:

isFinishing() 用於判斷 Activity 是否正在 finish。
isDestroy() 用於判斷 Activity 是否已經 destroy。
isFinishing() 返回 true 後 isDestroy() 纔會返回 true。
一、isFinishing()

   /**
     * Check to see whether this activity is in the process of finishing,
     * either because you called {@link #finish} on it or someone else
     * has requested that it finished.  This is often used in
     * {@link #onPause} to determine whether the activity is simply pausing or
     * completely finishing.
     *
     * @return If the activity is finishing, returns true; else returns false.
     *
     * @see #finish
     */
    public boolean isFinishing() {
        return mFinished;
    }

如註釋所說,isFinishing 可以用在 onPause 中判斷,該 Activity 是單純的 pause,還是正在 finish。

isFinishing 只是簡單地返回 mFinished 的值,而 mfinished 在 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 (ActivityManager.getService()
                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
                    mFinished = true;
                }
            } catch (RemoteException e) {
                // Empty
            }
        } else {
            mParent.finishFromChild(this);
        }

        // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
        // be restored now.
        if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
            getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
                    mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
        }
    }


二、isDestroy()

isDestroy() 也只是返回 mDestroyed 的值。

   /**
     * Returns true if the final {@link #onDestroy()} call has been made
     * on the Activity, so this instance is now dead.
     */
    public boolean isDestroyed() {
        return mDestroyed;
    }

mDestroyed 在 performDestroy() 中被賦值,在 onDestroy 執行前賦值。

final void performDestroy() {
        mDestroyed = true;
        mWindow.destroy();
        mFragments.dispatchDestroy();
        onDestroy();
        writeEventLog(LOG_AM_ON_DESTROY_CALLED, "performDestroy");
        mFragments.doLoaderDestroy();
        if (mVoiceInteractor != null) {
            mVoiceInteractor.detachActivity();
        }
    }

三、分析

看一下 Activity finish 的流程:

finish//【Activity】
    ActivityManagerNative.getDefault().finishActivity//【AMS】
        tr.stack.requestFinishActivityLocked//【ActivityStack】
        finishActivityLocked
        finishCurrentActivityLocked
        destroyActivityLocked
            r.app.thread.scheduleDestroyActivity//【ApplicationThread】                        
                handleDestroyActivity//【ActivityThread】
                performDestroyActivity
                    mInstrumentation.callActivityOnDestroy//【Instrumentation】
performDestroy//【Activity】
onDestroy


從上面 finish() 的源碼可以看出,當 ActivityManagerNative.getDefault().finishActivity 方法返回 true 後,mFinished 會被賦值。

在 finishActivity 內會調用 requestFinishActivityLocked,requestFinishActivityLocked 內會調 finishActivityLocked,finishActivityLocked 執行完後,requestFinishActivityLocked 就會返回 true。

finishActivityLocked 內會調用 r.app.thread.scheduleDestroyActivity,所以 r.app.thread.scheduleDestroyActivity 執行完後,mFinished 就被賦爲 true。

在這裏插入圖片描述

而 mDestroyed 會在 r.app.thread.scheduleDestroyActivity 執行後,轉移到主線程的 handler 裏再進行一些操作後才被賦爲 true。

所以,mFinished 爲 true 比 isDestroyed 爲 true 要早。即 isFinishing() 返回 true 後 isDestroy() 纔會返回 true。

邏輯上講也是這樣,先進行 finishing,然後才能 destroyed。

當需要使用 Activity 時,判斷 activity != null && !activity.isFinishing() 即可。
 


延伸:

Activity onDestroy() 調用研究

剛剛一個BUG讓我發現,如果 activity 實現了一個回調接口,然後使用 this 設置給需要回調接口的方法,這種應用場景比較常見,最常見的就是實現 onClickListener 接口,然後 findViewById().setOnClickListenr(this)

如果,這個回調接口設置到了一個靜態對象(單例模式),當 activity finish() 的時候(按返回鍵,回到桌面),則activity 不會被調用 onDestroy() ,原因可能是 activity 對象還在被引用!

此時你再點擊圖標回到應用,onCreate() 再次調用!

很明顯,如果你把資源釋放放在了 onDestroy() 裏面,就會導致內存泄露!

那有沒有解決辦法呢?有的

你可以在 onPause() 方法裏面判斷 isFinishing() ,正常調用 finish() 後 activity 的回調過程是 onPause、onStop、onDestroy ,倘若出現上面的情況,只到 onPause!但是 isFinishing() 標誌還是爲 true !你可以釋放資源了。 
 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章