前言
今天在調試程序時,發現在某一Activity上點擊返回鍵會調用該Activity的onActivityResult()方法。我一開始用log,后來用斷點跟蹤調試半天,還是百思不得其解。因為之前其他的Activity的LaunchMode都是Normal,沒有特殊設定,這個Activity由於需求改成了singleTop。直到我確定沒有一個地方是代碼主動觸發的,我才想到了跟Activity的LaunchMode是否有關。
探索
在Google上搜索android activity onactivityresult singTop找到了一些問題。
stackoverflow
stackoverflow上有些人跟我遇到的問題類似。比如說有一位開發者把Activity設置成了singleTask模式,onActivityResult就收不到任何結果了。當他把singleTask模式改回標准模式,又恢復正常。
這個問題下面給出的答案中,有一位說startActivityForResult的文檔中有這么一句話:
For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.
意思是:比如說,如果你正加載的activity使用了singleTask的加載模式,它不會在你的棧中運行,而且這樣你會馬上收到一個取消的結果。
即在onActivityResult里馬上得到一個RESULT_CANCEL.
他還補充說沒有很好的補救方法。可以試試用監聽廣播的方法。
另一個stackoverflow的問題中,有人直接回答了不能再singleInstance或singleTop模式下使用startActivityForResult()方法,不僅被采納了,票數還不低。
剩下的一個stackoverflow問題中,有人說把singleTask改成singleTop就會正常,得到高達59票並被采納。實際上我用的就是singTop,可是onActivityResult還是無緣無故被調用了。
startActivityForResult的文檔:
public void startActivityForResult (Intent intent, int requestCode, Bundle options)
Added in API level 16
Launch an activity for which you would like a result when it finished. When this activity exits, your onActivityResult() method will be called with the given requestCode. Using a negative requestCode is the same as calling startActivity(Intent) (the activity is not launched as a sub-activity).
加載一個Activity,當它結束時你會得到結果。當這個Activty退出了,你的onActivityResult()方法會根據給出的requestCode被調用。使用一個負的requestCode和調用startActivity(intent)一樣(activity不被加載成子activity)
Note that this method should only be used with Intent protocols that are defined to return a result. In other protocols (such as ACTION_MAIN or ACTION_VIEW), you may not get the result when you expect. For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result.
注意這個方法只能用於被定義要返回結果的Intent協議。在其他協議中(譬如ACTION_MAIN或ACTION_VIEW),你可能在你想得到結果時得不到。比如,當你正載入的Activity使用的singleTask加載模式,它不會在你的棧中運行,這樣你會立馬得到一個取消的結果。
As a special case, if you call startActivityForResult() with a requestCode >= 0 during the initial onCreate(Bundle savedInstanceState)/onResume() of your activity, then your window will not be displayed until a result is returned back from the started activity. This is to avoid visible flickering when redirecting to another activity.
有一個特例是,當你在初始的onCreate()方法或onResume()方法中用一個大於等於0的請求碼調用startActivityForResult(),你的窗口在被啟動的Activity返回結果前不會顯示。這是為了避免跳轉到另一Activity時可見的閃爍。
This method throws ActivityNotFoundException if there was no Activity found to run the given Intent.
如果運行所給Intent的Activity沒被找到,該方法會拋出ActivityNotFoundException異常。
Activity的加載模式
Use Cases | Launch Mode | Multiple Instances? | Comments |
---|---|---|---|
Normal launches for most activities | "standard " |
Yes | Default. The system always creates a new instance of the activity in the target task and routes the intent to it. |
"singleTop " |
Conditionally | If an instance of the activity already exists at the top of the target task, the system routes the intent to that instance through a call to itsonNewIntent() method, rather than creating a new instance of the activity. |
|
Specialized launches (not recommended for general use) |
"singleTask " |
No | The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to itsonNewIntent() method, rather than creating a new one. |
"singleInstance " |
No | Same as "singleTask" , except that the system doesn't launch any other activities into the task holding the instance. The activity is always the single and only member of its task. |
singleTop模式,可用來解決棧頂多個重復相同的Activity的問題。
singleTask模式和后面的singleInstance模式都是只創建一個實例的。
當intent到來,需要創建singleTask模式Activity的時候,系統會檢查棧里面是否已經有該Activity的實例。如果有直接將intent發送給它。
singleInstance模式解決了這個問題(繞了這么半天才說到正題)。讓這個模式下的Activity單獨在一個task棧中。這個棧只有一個Activity。導游應用和google地圖應用發送的intent都由這個Activity接收和展示。
總結
后來我改變了onActivityResult里面ResultCode為RESULT_OK時刷新界面的具體實現方法,可是onActivityResult還是會自己被調用,只是暫時沒觸發任何bug,可它還是個定時炸彈啊。
以后在選擇Activity的加載模式時,要考慮onActivtyResult方法與之存在沖突。
參考
- http://stackoverflow.com/questions/8960072/onactivityresult-with-launchmode-singletask
- http://developer.android.com/reference/android/app/Activity.html#startActivityForResult%28android.content.Intent,%20int%29
- http://stackoverflow.com/questions/7910840/android-startactivityforresult-immediately-triggering-onactivityresult
- http://stackoverflow.com/questions/3354955/onactivityresult-called-prematurely