Activity中的onActivityResult
在进行界面间的跳转和传递数据的时候,我们有的时候要获得跳转之后界面传递回来的状态,数据等信息。这个时候,我们不一定需要使用Intent进行跳转回原先设置的界面,而是使用onActivityResult方法就可以解决这个问题
Activity的使用流程如下实例:
public class MyActivityA extends AppCompatActivity implements View.OnClickListener {
public final int REQUEST_CODE_B = 1;
public final int REQUEST_CODE_C = 2;
private Button buttonB;
private Button buttonC;
private Intent intent;
private TextView result_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_activity_a);
buttonB = findViewById(R.id.btn_B);
buttonC = findViewById(R.id.btn_C);
result_text = findViewById(R.id.result_text);
buttonB.setOnClickListener(this);
buttonC.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_B:
intent = new Intent(MyActivityA.this,MyActivityB.class);
startActivityForResult(intent,REQUEST_CODE_B);
break;
case R.id.btn_C:
intent = new Intent(MyActivityA.this,MyActivityC.class);
startActivityForResult(intent,REQUEST_CODE_C);
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode) {
case REQUEST_CODE_B:
case REQUEST_CODE_C: //返回的结果是来自于Activity C
if (resultCode == Activity.RESULT_OK) {
result_text.setText(data.getStringExtra("respond"));
} else {
result_text.setText("No Name Activity");
}
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
public class MyActivityB extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_b);
Button btn = findViewById(R.id.b_back_a);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("respond", "Hello,I'm B Activity.");
setResult(Activity.RESULT_OK, intent);
finish();
}
});
}
}
Fragment中的onActivityResult
大家或许有遇到这个神坑,在Fragment中使用startActivityForResult能够成功,可是在Fragment中的onActivityResult却无法被调用。其实在Fragment中使用startActivityForResult之后,onActivityResult的调用是从activity中开始的(即会先调用activity中的onActivityResult)。
只嵌套了一层Fragment(比如activity中使用了viewPager,viewPager中添加了几个Fragment)
在这种情况下要注意几个点:
1.在Fragment中使用startActivityForResult的时候,不要使用getActivity().startActivityForResult,而是应该直接使startActivityForResult()。
2.如果activity中重写了onActivityResult,那么activity中的onActivityResult一定要加上super.onActivityResult(requestCode, resultCode, data)。
如果违反了上面两种情况,那么onActivityResult只能够传递到activity中的,无法传递到Fragment中的。
没有违反上面两种情况的前提下,可以直接在Fragment中使用startActivityForResult和onActivityResult,和在activity中使用的一样。
回到问题本身,onActivityResult的使用很麻烦,为什么不设计成回调呢?
假设可以用回调,那么下图中的1、3可以放在一起,达到高内聚的效果,更加易读也易懂,但是这样写是否可行呢?
然是不可行了,假设在操作Activity B时,由于内存回收或者策略等原因导致Activity A被销毁了,那么ActivityB在调用setResult时会重新创建一个Activity A',但是此时已经不再是Activity A了,我们知道匿名内部类持有外部类的引用,所以在刚开始new OnResultCallback时此匿名内部类持有的还是Activity A的对象引用,但是此时Activity A的对象已经销毁了,也就造成onResulet的方法中的mTextView根本拿不到其所在的对象。这样就会发生异常。
那如果通过Fragment中的onActivityResult代替Activity中的onActivityResult,再进行回调处理可以吗?
可以基于反射和注解处理器来实现Fragment的回调实现。首先在ActivityA中创建一个空的Fragment,然后Fragment中的onActivityResult被触发,但是这个也存在引用变换的问题,可以通过反射去访问去拿到一个新的引用aActivity',把这个新的引用aActivity'替代旧的aActivity引用,那么问题就解决了。(其中还有其他很多问题需要处理,后续更新~~)