您的位置:首页 > 移动开发 > Android开发

关于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

<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源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android fragment result