本篇文章主要是記錄Activity各種疑難雜癥,在平時使用過程中遇到的坑點,以及Activity使用難點,歡迎各位拍磚。
1.setResult和finish的順序關(guān)系
當(dāng)ActivtyA通過startActivityForResult啟動ActivityB的時候,從ActivityB頁面返回并設(shè)置setResult的時候,會回調(diào)ActivityA的onActivityResult方法,并可以通過setResult傳值,有時候會遇到setResult傳值不起作用的情況:

上面這張圖我是在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é)果如下:

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

此時Activity不會重新創(chuàng)建,而只會調(diào)用onConfigurationChanged()方法。在targetSdkVersion的值小于或等于12時,只需要配置orientation就可以得到同樣的結(jié)果。
所以旋轉(zhuǎn)手機屏幕時,activity生命周期的變化和configChanges屬性有關(guān),配置相關(guān)屬性就不會重新走onCreate流程,不配置的話就會先走銷毀流程,再走onCreate流程。
注:configChanges屬性參數(shù)如下表:

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屬性無效!