关于Activity与Fragment混用中对于startActivityForResult方法的解析
2016-05-22 19:38
423 查看
本博文是对于Activity与Fragment混用中关于startActivityForResult的个人理解,如有错误之中望指正。
先来看下测试应用的场景流程
场景一:基础场景 Activity.startActivityForResult()
Created with Raphaël 2.1.0MainActivityMainActivityTargetActivityTargetActivitystartActivityForResult()setResult()
场景二:Fragment.startActivityForResult()
Created with Raphaël 2.1.0MainActivityMainActivityTestFragmentTestFragmentTargetActivityTargetActivitystartActivityForResult()setResult()targetFragment.onActivityResult()
那么我们现在需要构建MainActivity、TestFragment、TargetActivity;
activity_main.xml
MainActivity主要代码
fragment_test.xml
TestFragment主要代码
activity_target.xml
TargetActivity主要代码:
分析:
场景一:基础应用就不做多言了
场景二:Fragment.startActivityForResult() 首先收到结果的是Activity.onActivityResult(),然后才是执行Fragment.onActivityResult();查看Fragment的源码:
由此可知其实fragment还是调用宿主Activity的startActivityForResult()方法,那么实际上返回的result是先返回到宿主Activity的onActivityResult(),然后才继续往fragment下发数据。那么这里会经常出现一种情况 当宿主Activity的onActivityResult()缺少对父类方法super.onActivityResult(requestCode, resultCode, data);调用时,fragment是接收不到返回的数据的。
那么通过查看super.onActivityResult()源码可知:
其中
Fragment targetFragment = mFragments.findFragmentByWho(who);
targetFragment.onActivityResult(requestCode&0xffff, resultCode, data);
才是使返回数据指向最终fragment的onActivityResult()。
那么针对网友提出的在fragment里通过fragmen.this.startActivityForResult()解决fragment无法接收返回数据的方法实际是行不通,决定因数是宿主activity的数据转发。
另外还有一种说法有的网友说直接通过在fragment.startActivityForResult(intent, Activity.RESULT_FIRST_USER);就可以直接接收到返回的数据,但是实际测试过程中并没有出现这种情况,可能是sdk版本差异吧,该demo所使用的版本是support-v4:23 对于startActivityForResult()方法上面也提到了是调用了宿主的方法,并不像网上说的fragment本身的方法。
针对以上两种情况,如果有网友有不同的见解可以进行回复。
当然还有一种情况,如果宿主Activity没有重写onActivityResult()方法的话,fragment是可以接受到返回数据的,因为默认去寻找目标fragment了。
附上demo源码
先来看下测试应用的场景流程
场景一:基础场景 Activity.startActivityForResult()
Created with Raphaël 2.1.0MainActivityMainActivityTargetActivityTargetActivitystartActivityForResult()setResult()
场景二:Fragment.startActivityForResult()
Created with Raphaël 2.1.0MainActivityMainActivityTestFragmentTestFragmentTargetActivityTargetActivitystartActivityForResult()setResult()targetFragment.onActivityResult()
那么我们现在需要构建MainActivity、TestFragment、TargetActivity;
activity_main.xml
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/Bt_StartActivityFromActivity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAllCaps="false" android:text="Activity.startActivityForResult" /> <TextView android:id="@+id/TV_callBack" android:layout_width="match_parent" android:layout_height="200dp" android:hint="Result" android:paddingLeft="5dp" /> <FrameLayout android:id="@+id/FragmentContent" android:layout_width="match_parent" android:layout_height="match_parent"></FrameLayout> </LinearLayout>
MainActivity主要代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_StartActivityFromActivity = (Button) findViewById(R.id.Bt_StartActivityFromActivity); tv_callBack = (TextView) findViewById(R.id.TV_callBack); bt_StartActivityFromActivity.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, TargetActivity.class); startActivityForResult(intent, TARGETACTIVITY_RESULTCODE); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //super.onActivityResult这一行很是重要 super.onActivityResult(requestCode, resultCode, data); if (requestCode == TARGETACTIVITY_RESULTCODE) { tv_callBack.setText(getDate()+" response result for MainActivity \n"+"resultCode is "+ resultCode); } }
fragment_test.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.pisces.TestFragment" android:orientation="vertical"> <Button android:id="@+id/Bt_StartActivityFromFragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAllCaps="false" android:text="Fragment.StartActivityForResult"/> <TextView android:id="@+id/TV_callBack" android:layout_width="match_parent" android:layout_height="200dp" android:hint="Result" android:paddingLeft="5dp" /> </LinearLayout>
TestFragment主要代码
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment view = inflater.inflate(R.layout.fragment_test, container, false); bt_StartActivityFromFragment = (Button) view.findViewById(R.id.Bt_StartActivityFromFragment); tv_callBack = (TextView) view.findViewById(R.id.TV_callBack); bt_StartActivityFromFragment.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getActivity(), TargetActivity.class); startActivityForResult(intent, TARGETACTIVITY_RESULTCODE); } }); return view; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == TARGETACTIVITY_RESULTCODE) { tv_callBack.setText(MainActivity.getDate() + " response result for TestFragment \n"+"resultCode is "+ resultCode); } }
activity_target.xml
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="RandomCode:" android:paddingLeft="5dp" /> <TextView android:id="@+id/TV_random" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <Button android:id="@+id/Bt_return" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAllCaps="false" android:text="return a randomCode as resultcode"/>
TargetActivity主要代码:
bt_return.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { returnBackData(); } }); private void returnBackData(){ Intent data = new Intent(); setResult(randomCode, data); finish(); }
分析:
场景一:基础应用就不做多言了
场景二:Fragment.startActivityForResult() 首先收到结果的是Activity.onActivityResult(),然后才是执行Fragment.onActivityResult();查看Fragment的源码:
/** * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's * containing Activity. */ public void startActivityForResult(Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); }
由此可知其实fragment还是调用宿主Activity的startActivityForResult()方法,那么实际上返回的result是先返回到宿主Activity的onActivityResult(),然后才继续往fragment下发数据。那么这里会经常出现一种情况 当宿主Activity的onActivityResult()缺少对父类方法super.onActivityResult(requestCode, resultCode, data);调用时,fragment是接收不到返回的数据的。
那么通过查看super.onActivityResult()源码可知:
/** * Dispatch incoming result to the correct fragment. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { mFragments.noteStateNotSaved(); int requestIndex = requestCode>>16; if (requestIndex != 0) { requestIndex--; String who = mPendingFragmentActivityResults.get(requestIndex); mPendingFragmentActivityResults.remove(requestIndex); if (who == null) { Log.w(TAG, "Activity result delivered for unknown Fragment."); return; } Fragment targetFragment = mFragments.findFragmentByWho(who); if (targetFragment == null) { Log.w(TAG, "Activity result no fragment exists for who: " + who); } else { targetFragment.onActivityResult(requestCode&0xffff, resultCode, data); } return; } super.onActivityResult(requestCode, resultCode, data); }
其中
Fragment targetFragment = mFragments.findFragmentByWho(who);
targetFragment.onActivityResult(requestCode&0xffff, resultCode, data);
才是使返回数据指向最终fragment的onActivityResult()。
那么针对网友提出的在fragment里通过fragmen.this.startActivityForResult()解决fragment无法接收返回数据的方法实际是行不通,决定因数是宿主activity的数据转发。
另外还有一种说法有的网友说直接通过在fragment.startActivityForResult(intent, Activity.RESULT_FIRST_USER);就可以直接接收到返回的数据,但是实际测试过程中并没有出现这种情况,可能是sdk版本差异吧,该demo所使用的版本是support-v4:23 对于startActivityForResult()方法上面也提到了是调用了宿主的方法,并不像网上说的fragment本身的方法。
针对以上两种情况,如果有网友有不同的见解可以进行回复。
当然还有一种情况,如果宿主Activity没有重写onActivityResult()方法的话,fragment是可以接受到返回数据的,因为默认去寻找目标fragment了。
附上demo源码
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories