Android關於Intent的思考:如何更好的啟動一個Activity
普通寫Intent的方法和缺陷
- 普通Activity A要呼叫起Activity B頁面會這麼寫:
Activity A:
Intent intent = new Intent(A.this, B.class);
intent.putExtra("is_index", message);
startActivity(intent);
Activity B:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String is_index = getIntent().getExtras().getString("is_index" );
...
}
- 上面的寫法是大多數Intent寫法,在發起方建立intent。但這種寫法在程式碼量大大增加的時候會出現一個問題。當Activity B在各種地方都會被呼叫起的時候,並且會傳入各種各樣不同的extra欄位時,會發現很混亂,哪些發起方使用了哪些extra欄位,每個欄位什麼意思,哪些是必須的等等問題。最終造成B程式碼可讀性變差,讓以後想要呼叫起B的頁面也不清楚需要傳入哪些extra。
優化寫Intent
- 同樣是Activity A要呼叫起Activity B頁面的例子:
Activity A:
Intent intent = B.newIndexIntent(this , message);
startActivity(intent);
Activity B:
private final static String IS_INDEX = "is_index";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
String is_index = getIntent().getExtras().getString(IS_INDEX);
...
}
...
/**
* 建立intent
* is_index 是否是首頁跳轉過來的
*/
public static Intent newIndexIntent(Context context, String message) {
Intent newIntent = new Intent(context, b.class);
newIntent.putExtra(IS_INDEX, message);
return newIntent;
}
- 用上面的方法可以保證所有extra全部定義在被呼叫起Activity的內部,對外不可見,並可以對每個extra有詳細的註釋(是否必須、在什麼地方呼叫等)。
思考
- 跳轉的時候是否可以直接寫為 B.newIndexIntent(this,text),因為 發起啟動的不是介面,而是上下文物件。是否可以直接做B.class裡面封裝一個啟動方法,裡面接受幾個引數,然後用傳過來的context啟動。但有一些特殊情況,如:啟動時為startActivityForResult,result的值最好還是放在啟動的類裡定義等。
附錄
- Intent中的各種FLAG
Intent intent = new Intent(this,xxx.class);
//如果activity在task存在,拿到最頂端,不會啟動新的Activity
intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
//如果activity在task存在,將Activity之上的所有Activity結束掉
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//預設的跳轉型別,將Activity放到一個新的Task中
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//如果Activity已經執行到了Task,再次跳轉不會在執行這個Activity
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
網上有關於Intent flag和taskAffinity的實驗結果, 我們來看下相關結論:
FLAG_ACTIVITY_NEW_TASK並不像官方文件所說的等同與singleTask.
在沒有任何其他flag組合和taskAffinity設定的情況下, 同一應用內FLAG_ACTIVITY_NEW_TASK啟動另外一個Activity, 不會在新的Task中建立例項, 也不會有例項複用.
FLAG_ACTIVITY_SINGLE_TOP作用等同與singleTop, 當Task的top Activity是該Activity時, Activity複用.
FLAG_ACTIVITY_CLEAR_TOP會clear top, 也就是說如果Task中有ABCD, 在D中啟動B, 會clear掉B以上的CD. CD銷燬.
注意, FLAG_ACTIVITY_CLEAR_TOP並不意味著重用, 預設Activity為standard模式的話, 只是會clear其top的其他Activity例項, 該Activity並不會重用, 而是也會銷燬, 然後建立一個新的該Activity例項來響應此Intent.
在沒有設定taskAffinity的情況下, 同一應用內FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP組合啟動另外一個Activity, 作用和單獨使用FLAG_ACTIVITY_CLEAR_TOP是一樣.(此點類同與第二點)
如taskAffinity解釋的一樣, 在我們沒有引入taskAffinity時(android:affinity=xxx.xxx.xxx), 同一個應用中, 使用各種Intent flag都並不會建立新的Task.
taskAffinity需結合FLAG_ACTIVITY_NEW_TASK使用, 此時會再新的Task中尋找/建立待啟動的Activity例項.
強烈建議 FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP結合使用,單獨使用FLAG_ACTIVITY_NEW_TASK可能會遇到問題(系統會在android:affinity=xxx.xxx.xxx的Task中找有沒有已經存在的A的例項, 發現Task中有. 於是乎, 想重用A. 然而並沒有能銷燬B, 讓A彈出來接收新的Intent.所以說, 這種情況下, Intent.FLAG_ACTIVITY_NEW_TASK必須結合Intent.FLAG_ACTIVITY_CLEAR_TOP來一起用)。
Intent Flag並不能代替launchMode, 至少在想重用Activity的情況下, 你需要做的是考慮launchMode而非Intent Flag.
個人理解, Intent Flag更多是傾向於用來做Task中的Activity組織. 而launchMode兼顧Task組織和Activity例項的重用.