关于startActivityForResult

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方法之后吗?

setResultfinish之前执行,只是把数据记录在Activity.mResultCodeActivity.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。
从代码可以看出setResultfinish类似生产者/消费者模型,setResult负责写入数据,finish负责读取数据。

线程安全问题

Activity.mResultCodeActivity.mResultData变量由Activity对象的锁进行保护,支持后台线程和 UI 线程分别进行setResultfinish

API设计/数据组装问题

底层 AMS 提供的接口的参数是setResultfinish的参数的组合形式,但是 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值