startActivityForResult使用场景是什么?requestCode、resultCode含义是什么?
使用场景
用户开始新的活动,并且希望得到新活动的某些信息。比如选择照片、选择联系人、选择收货地址、进行某块数据编辑工作等。
requestCode
解决的是「区分多个异步任务」的问题。与其他异步 API 的设计类似,如果没有这个信息,那么 Activity 在收到响应时会进入混乱的状态。比如他不知道自己得到的是选择照片还是选择联系人的结果。
该信息会发送到 AMS 那边的ActivityRecord.requestCode
变量进行记录,Client 端新 Activity 并不知道这个信息。
- 为什么
requestCode < 0
时收不到结果?
ActivityStarter 收到startActivityLocked
时,写入ActivityRecord.resultTo
变量为空。
if (requestCode >= 0 && !sourceRecord.finishing) {
// 只有非负数时新的 ActivityRecord 对象的 resultTo 变量才指向发起者 ActivityRecord 对象
resultRecord = sourceRecord;
}
在 ActivityStack 收到finishActivityResultsLocked
时,读取ActivityRecord.resultTo
变量为空,结果数据不会添加到源ActivityRecord.results
变量。
在 ActivityStack 收到resumeTopActivityInnerLocked
时,读取ActivityRecord.results
数组为空,不会分发结果数据,这样源Activity也就没有结果回调了。
resultCode
异步调用结果码,告诉调用者成功/失败/其它信息。
该信息由被调用 Activity/Framework 写入,并经过 AMS 传递给源 Activity。
Activity A启动B的时候,在B中何时执行setResult?setResult是否可以位于Activity的finish方法之后吗?
setResult
在finish
之前执行,只是把数据记录在Activity.mResultCode
和Activity.mResultData
变量中。
- 最早 Activity 构造器阶段
- 最晚 Activity.finalize 内存回收阶段
// Home 键 + 不保留后台 Activity 可触发 onDestroy
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy() called");
new ReqGC().start();
}
@Override
protected void finalize() throws Throwable {
Log.d(TAG, "finalize() called");
finish();
super.finalize();
}
@Override
public void finish() {
Log.d(TAG, "finish() called");
setResult(RESULT_OK, new Intent().putExtra("key", "resultData"));
super.finish();
}
// 不泄漏 Activity 对象
static class ReqGC {
public void start() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
System.gc();
handler.postDelayed(this, 10);
}
}, 10);
}
}
如果位于finish
之后执行,那信息无法传递给源 Activity。
从代码可以看出setResult
和finish
类似生产者/消费者模型,setResult
负责写入数据,finish
负责读取数据。
线程安全问题
Activity.mResultCode
和Activity.mResultData
变量由Activity对象的锁进行保护,支持后台线程和 UI 线程分别进行setResult
和finish
。
API设计/数据组装问题
底层 AMS 提供的接口的参数是setResult
和finish
的参数的组合形式,但是 Activity 为什么把一个接口拆分成两个接口给开发者使用?
使用方便。很多情况下调用者只关心finish
,不需要理解太多的信息。
API内部原理/数据处理流程
关键节点:
- Client 端通过 AMP 把数据发送给 Server 端 AMS Binder 实体
- AMS 把数据包装成 ActivityResult 并保存在源 ActivityRecord 的 results 变量中
- AMS 通过 ApplicationThreadProxy 向 Client 端发送 pause 信息让栈顶 Activity 进入 paused 状态,并等待 Client 端回复或超时
- AMS 接收 Client 端已 paused 信息,恢复下一个获取焦点的 Activity ,读取之前保存在
ActivityRecord.results
变量的数据派发给 Client 端对应的 Activity - Client 端数据经过 ApplicationThread 对象、ActivityThread 对象的分发最后到达 Activity