onActivityResult不響應的情況分析和排查

小細節問題 ,又長見識了。。。。


原文:  http://blog.sina.com.cn/s/blog_5da93c8f0101o2k1.html


大家都知道,可以通過使用 startActivityForResult() 和 onActivityResult() 方法來傳遞或接收參數。

但你是否遭遇過onActivityResult()不執行或者未按預想的那樣執行的情況呢?

這裏我總結了三種情況:

1、執行startActivityForResult,沒等到被調用的 Activity 返回,onActivityResult() 就被執行了。


找了很久,終於通過小道消息得知,這與 Activity 的加載模式(launchMode)有關,該屬性可以在 AndroidManifest.xml 中設置。
原先將其設爲 singleInstance或singleTask經測試,所有需要傳遞或接收的 Activity 不允許設置該屬性,或只能設爲標準模式,否則系統將在 startActivityForResult() 後直接調用 onActivityResult()。


Note that this method should only be used with Intent protocols
* that are defined to return a result. In other protocols (such as
* {@link Intent#ACTION_MAIN} or {@link Intent#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.

2、兩個activity傳遞數據和返回數據時,請求方的onActivityResult始終無響應,通過debug調試模式也沒見調用該方法。查看了 各種配置和程序代碼,均未發現有錯誤之處。後來仔細閱讀API說明,恍然大悟,原來是調用startActivityForResult的參數問題,即調 用時這樣:
startActivityForResult(intent, 0);是第二個參數的問題,該參數必須大於0才能在返回值並激活onActivityResult方法

我最開始是用的一個activity默認的常量:RESULT_OK,跟蹤了代碼後發現,該常量的值爲-1,當然沒法激活 onActivityResult方法了,隨後隨便修改爲一個大於0的整數,程序即通跑成功。
startActivityForResult(intent, 1); //這樣就行了

API描述:
@requestCode If >= 0, this code will be returned in onActivityResult() when the activity exits.

 3、在TabHost的子Activity中startActivityForResult調用其他Activity時候遭遇到onActivityResult方法不響應的問題。可以通過調用Activity的getCallingActivity()查看要接受數據的Activity。

API這麼解釋的:

Return the name of the activity that invoked this activity. This is
* who the data in {@link #setResult setResult()} will be sent to.

舉個列子,有兩個ActivityA和B,A中執行startActivityForResult(1,new Intent(A,B.class));

即由A調到B,再B執行setResult後執行getCallingActivity(),顯示A。


解決辦法如下:

1.通過父Activity啓動其他Activity;

2.實現父Activity的onActivityResult方法,將該處接收到的請求轉發給當前活動的子Activity;

3.自定義一個轉發接口用來實現第2步中的轉發功能;

4.子Activity中實現第3步接口中的方法用來接收返回信息;


代碼如下:

1.通過父Activity啓動其他Activity
1 getParent().startActivityForResult(new Intent(...), REQUEST_CODE); 
2.實現父Activity的onActivityResult方法

3.自定義接口
public interface OnTabActivityResultListener {

public void onTabActivityResult(int requestCode, int resultCode, Intent data);

}

4.子Activity需要實現onTabActivityResult方法
@Override

public void onTabActivityResult(int requestCode, int resultCode, Intent data) {

if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {

//實現該處邏輯
        ...

}

}




總結:
凡是Activity本身含有上次父類的情況都不能直接使用startActivityForResult,而要通過getParent(),通過父類調用此方法。


此種情況也適用於多重Fragment嵌套使用的情況。


理論上使用FragmentActivity 和 Fragment組合時,在Fragment中調用startActivityForResult方法,實際上是調用Fragment所依付的Activity的startActivityForResult方法。

然後Fragment  Activity會先響應自身的onActivityResult方法,再傳遞到當前活動的Fragment中。此時,通過重載Fragment的onActivityResult方法可以接受返回事件。

這裏需要注意,如果重載了FragmentActivity的 onActivityResult方法,一定要調用super. onActivityResult(),否則Fragment中的 onActivityResult方法不會被調用。 


4、FragmentActivity和Fragment組合使用,且使用多層Fragment組合(即Fragment內部有嵌套)。在底層Fragment中執行startActivityForResult方法後,Fragment的onActivityResult方法沒有被調用。

我重載了FragmentActivity的onActivityResult方法,也增加了super.onActivityResult()。通過調試發現,FragmentActivity的onActivityResult方法執行了,但是沒有往下傳遞成功。


後來翻看源碼:

FragmentActivity中的onActivityResult方法這樣寫的:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
int index = requestCode>>16;
if (index != 0) {
index--;
if (mFragments.mActive == null || index < 0 || index >= mFragments.mActive.size()) {
Log.w(TAG, "Activity result fragment index out of range: 0x"
+ Integer.toHexString(requestCode));
return;
}
Fragment frag = mFragments.mActive.get(index);
if (frag == null) {
Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ Integer.toHexString(requestCode));
}
frag.onActivityResult(requestCode&0xffff, resultCode, data);
return;
}

super.onActivityResult(requestCode, resultCode, data);
}



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