关于startActivityForResult

简介: startActivityForResult使用场景是什么?requestCode、resultCode含义是什么?使用场景用户开始新的活动,并且希望得到新活动的某些信息。

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
目录
相关文章
|
Android开发
Android onActivityResult()的属性与用法
Android onActivityResult()的属性与用法
165 1
|
存储 Android开发
Android startActivityForResult和onActivityResult的基本用法
Android startActivityForResult和onActivityResult的基本用法
118 0
NullPointerException:method 'android.content.BroadcastReceiver.onReceive' on a null object reference
NullPointerException:method 'android.content.BroadcastReceiver.onReceive' on a null object reference
startActivityForResult解析
startActivityForResult解析
133 0
startActivityForResult解析
Activity与Fragment的onActivityResult细节
在Fragment中跳转到另一个Activity,返回时是调用Activity的onActivityResult呢?还是调用Fragment的onActivityResult呢? 我当然知道,只不过我再碰到时忘记了,然后每次忘记都要从新去网上找,不如做个Test然后记录下来。
1277 0