【Android】專治Activity各種疑難雜癥

本篇文章主要是記錄Activity各種疑難雜癥,在平時使用過程中遇到的坑點,以及Activity使用難點,歡迎各位拍磚。

1.setResult和finish的順序關(guān)系

當(dāng)ActivtyA通過startActivityForResult啟動ActivityB的時候,從ActivityB頁面返回并設(shè)置setResult的時候,會回調(diào)ActivityA的onActivityResult方法,并可以通過setResult傳值,有時候會遇到setResult傳值不起作用的情況:


image.png

上面這張圖我是在SecordActivity的onPause方法里調(diào)用的setResult:

@Override
    protected void onPause() {
        super.onPause();
        Intent intent = new Intent();
        intent.putExtra("name","來自secord的data");
        setResult(101,intent);
        Log.e("wangkeke","secord---onPause");
    }

可以發(fā)現(xiàn)setResult傳遞name值失敗,那么setResult()應(yīng)該在什么時候調(diào)用呢?看下setResult和finish的源碼:

    public final void setResult(int resultCode, Intent data) {
        synchronized (this) {
            mResultCode = resultCode;
            mResultData = data;
        }
    }

    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返回result是在finish的時候,也就是說調(diào)用setResult()方法必須在finish()之前。所以在onPause、onStop、onDestroy方法中調(diào)用setResult()可能會返回失敗。

如果你需要在點擊back鍵的時候setResult,可以用以下寫法:

    @Override
    public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("name","來自secord的data");
        setResult(101,intent);
        //下面這行代碼會去調(diào)用finish方法
        super.onBackPressed();
    }

2.onNewIntent注意事項以及SingleTask的坑

觸發(fā)時機:activity任務(wù)棧中已存在要啟動的Activity實例,則不會再創(chuàng)建新實例,而是執(zhí)行Activity的onNewIntent(intent)方法。

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        //更新intent
        setIntent(intent);
}

如果沒有調(diào)用setIntent(intent),則getIntent()獲取的數(shù)據(jù)可能不是你所期望的。但是使用onNewIntent的參數(shù)intent,是可以獲得正確的數(shù)據(jù)的。

注意:對于Activity的啟動模式這里不多介紹,但是當(dāng)要啟動的Activity的啟動模式設(shè)置為SingleTask時,并且啟動Activity使用的是startActivityforResult方法,那么此時SingleTask會失效。
具體原因分析點這里!

3.旋轉(zhuǎn)手機屏幕時Activity的生命周期和onConfigurationChanged()的調(diào)用時機

我在Android8.0上Activity未配置configChanges時的測試結(jié)果如下:

image.png

配置configChanges為android:configChanges="orientation|screenSize"時,結(jié)果如下:
image.png

此時Activity不會重新創(chuàng)建,而只會調(diào)用onConfigurationChanged()方法。在targetSdkVersion的值小于或等于12時,只需要配置orientation就可以得到同樣的結(jié)果。


所以旋轉(zhuǎn)手機屏幕時,activity生命周期的變化和configChanges屬性有關(guān),配置相關(guān)屬性就不會重新走onCreate流程,不配置的話就會先走銷毀流程,再走onCreate流程。
注:configChanges屬性參數(shù)如下表:
官網(wǎng)截圖.png

4.onSaveInstanceState()和onRestoreInstanceState()

onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法,它們不同于 onCreate()、onPause()等生命周期方法,并不一定會被觸發(fā)。

當(dāng)應(yīng)用遇到意外情況(如:內(nèi)存不足、按Home鍵等)由系統(tǒng)銷毀一個Activity時,onSaveInstanceState() 會被調(diào)用。但當(dāng)用戶主動去銷毀一個Activity時,例如在應(yīng)用中按返回鍵,onSaveInstanceState() 就不會被調(diào)用。

onSaveInstanceState()的調(diào)用遵循一個重要原則,即當(dāng)系統(tǒng)存在 “未經(jīng)你許可” 銷毀了我們的 activity 的可能時,則 onSaveInstanceState() 會被系統(tǒng)調(diào)用,且調(diào)用將發(fā)生在 onPause() 之前。

onRestoreInstanceState() 被調(diào)用的前提是,activityA “確實” 被系統(tǒng)銷毀了,且 activity A 被重新創(chuàng)建。當(dāng) activityA 未被重新創(chuàng)建時,該方法不會被調(diào)用,onRestoreInstanceState() 在 onStart() 和 onResume() 之間調(diào)用。

注意:onRestoreInstanceState()一旦被調(diào)用,其參數(shù)bundle一定是有值的,而onCreate則不一定。

5. TaskAffinity屬性

我們知道,每個APP默認(rèn)只有一個任務(wù)棧,以應(yīng)用的包名來命名,Activity的TaskAffinity屬性可以新建任務(wù)棧。

如果單獨設(shè)置TaskAffinity屬性的話是沒有任何效果的,只有Activity的launchMode設(shè)置成singleTask的時候才會生效的,在AndroidManifest的Activity中可以配置TaskAffinity這個屬性。

注意:
1.TaskAffinity的值應(yīng)該是形如xxx.xxx.xxx的形式,如果沒有包含 . 的話是安裝不了的;
2.如果不指定TaskAffinity的話,默認(rèn)的任務(wù)棧名稱就是應(yīng)用包名。

注意:采用startActivityForResult的方式啟動Activity時,TaskAffinity屬性無效!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容