关于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
目录
相关文章
|
9月前
|
定位技术 Android开发
Intent在Android中的几种用法
Intent在Android中的几种用法
128 1
|
XML 存储 前端开发
Android:Intent 和 Intent 过滤器
在前 4 篇文章中,我们介绍了 Android 四大组件的基础知识,四大组件是构成我们 App 的基础,也是 Android 系统设计的最佳体现。各个组件之间完全是解耦的,如果想访问其他组件或者启动其他组件可以使用 Intent 来操作。在四种组件类型中,有三种(Activity、Service 和 Broadcast)均可以通过异步消息 Intent 进行启动。Intent 会在运行时对各个组件进行互相绑定。所以我们可以把 Intent 当作是各个组件之间的信使(无论该组件是自己 App 的还是其他 App)。
165 0
Android:Intent 和 Intent 过滤器
|
存储 安全 物联网
Android:Android 应用权限详解
这篇文章为大家系统的梳理一下 Android 权限相关的知识,在日常开发中,我们都用过权限,但是对于权限的一些细节我们可能掌握的还不够全面,这篇文章会全面的为大家介绍权限相关的知识。
1323 0
Android:Android 应用权限详解
|
Android开发
Android 振动器的使用详解
Android 振动器的使用详解
122 0
|
安全 编译器 API
Now in Android #15 —— 最新 Android 知识分享
Now in Android #15 —— 最新 Android 知识分享
Now in Android #15 —— 最新 Android 知识分享
|
传感器 存储 SQL
Android 值得学【Android 专题 2】
Android 系统到底提供了哪些东西,供我们可以开发出优秀的应用程序。 四大组件 Android 系统四大组件分别是活动(Activity)、服务(Service)、广播接收器(BroadcastReceiver)和内容提供器(Content Provider)。其中活动是所有 Android 应用程序的门面,凡是在应用中你看得到的东西,都是放在活动中的。而服务就比较低调了,你无法看到它,但它会一直在后台默默地运行,即使用户退出了应用,服务仍然是可以继续运行的。广播接收器可以应用接收来自各处的广播消息,比如电话、短信等,当然你的应用同样也可以向外发出广播消息。内容提供器则为应用程序之间共享数
127 0
|
Android开发 数据格式 XML
|
定位技术 Android开发 UED