「Android」从其他Activity获取结果:registerForActivityResult()

简介

  • Activity Result APIs 可以取代 startActivityForResult 方法,去启动Activity以获取结果
  • Activity Result APIs 可以取代 requestPermissions 方法,去请求运行时权限

背景

启动一个 activity(无论是本应用中的 activity 还是其他应用中的 activity)不一定是单向操作,也可以启动另一个 activity 并接收返回的结果。
常见的场景是调用系统相机、调用相册获取照片、调用通讯录、获取部分特殊权限等,传统方式通常是通过 Intent 携带数据,然后使用 startActivityForResult 方法来启动下一个 Activity,然后通过 onActivityResult 来接收返回的数据。
传统方式的问题在于:

  • 在启动 activity 以获取结果时,可能会出现进程和 activity 因内存不足而被销毁的情况
  • onActivityResult 回调方法嵌套耦合严重,逻辑混乱导致难以维护

为启动Activity获取的结果注册结果回调

基于上述存在问题,Activity Result APIs 将启动 Activity 的结果回调,与启动 Activity 的逻辑进行了分离。

位于 ComponentActivity 或 Fragment 中时,Activity Result API 提供了 registerForActivityResult() API,用于注册结果回调。
registerForActivityResult() 接受 ActivityResultContractActivityResultCallback 作为参数,并返回 ActivityResultLauncher,用来启动另一个 activity,其中:

  • ActivityResultContract 定义生成结果所需的输入类型以及结果的输出类型。这些 API 可为拍照和请求权限等基本 intent 操作提供默认协定,同时还可以创建自定义协定。
  • ActivityResultCallback 是单一方法接口,带有 onActivityResult() 方法,可接受 ActivityResultContract 中定义的输出类型的对象:
ActivityResultLauncher mGetContent = registerForActivityResult(new GetContent(),    new ActivityResultCallback() {        @Override        public void onActivityResult(Uri uri) {            // Handle the returned Uri        }});

启动Activity以获取结果

registerForActivityResult() 仅为启动 Activity 获取的结果注册结果回调,但它本身不会并启动另一个 activity 并发出结果请求。启动 Activity 的操作由 registerForActivityResult() 返回的 ActivityResultLauncher 的实例对象负责。

如果存在输入参数,ActivityResultLauncher 的实例对象会根据输入参数去匹配 ActivityResultContract 的类型。调用ActivityResultLauncher 的实例对象的 launch() 方法,会启动 Activity 并获取结果。当用户完成后续 activity 并返回时,系统将执行 ActivityResultCallback 中的 onActivityResult() 方法。

ActivityResultLauncher mGetContent = registerForActivityResult(new GetContent(),    new ActivityResultCallback() {        @Override        public void onActivityResult(Uri uri) {            // Handle the returned Uri        }});@Overridepublic void onCreate(@Nullable savedInstanceState: Bundle) {    // ...    Button selectButton = findViewById(R.id.select_button);    selectButton.setOnClickListener(new OnClickListener() {        @Override        public void onClick(View view) {            // Pass in the mime type you'd like to allow the user to select            // as the input            mGetContent.launch("image/*");        }    });}
注意:由于在调用 launch() 与触发 onActivityResult() 回调的两个时间点之间,进程和 activity 可能会被销毁,因此,处理结果所需的任何其他状态,都必须与这些 API 分开保存和恢复。

预定义Contract

在 Activity Result APIs 中提供了一系列预定义 Contract 供开发者去分别启动Activity以获取结果请求运行时权限

  • StartActivityForResult:通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
  • RequestMultiplePermissions:用于请求一组权限
  • RequestPermission:用于请求单个权限
  • TakePicturePreview:调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
  • TakePicture:调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
  • TakeVideo:调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。
  • PickContact:从通讯录APP获取联系人
  • GetContent:提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。默认情况下,它增加了 Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。
  • CreateDocument:提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
  • OpenMultipleDocuments:提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
  • OpenDocumentTree:提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。

使用以上预定义 Contract 进行开发的经典例子:

StartActivityForResult

    ActivityResultLauncher activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback() {        @Override        public void onActivityResult(ActivityResult result) {        }    });    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));        activityResultLauncher.launch(intent);    }

RequestMultiplePermissions

    ActivityResultLauncher activityResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback>() {        @Override        public void onActivityResult(Map result) {        }    });    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE};        activityResultLauncher.launch(permissions);    }

新旧对比:onActivityResult & Activity Result APIs

旧:

public void openSomeActivityForResult() {    Intent intent = new Intent(this, SomeActivity.class);    startActivityForResult(intent, 123);}@Overrideprotected void onActivityResult (int requestCode, int resultCode, Intent data) {    if (resultCode == Activity.RESULT_OK && requestCode == 123) {        doSomeOperations();    }}

新:

// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayedActivityResultLauncher someActivityResultLauncher = registerForActivityResult(        new ActivityResultContracts.StartActivityForResult(),        new ActivityResultCallback() {            @Override            public void onActivityResult(ActivityResult result) {                if (result.getResultCode() == Activity.RESULT_OK) {                    // There are no request codes                    Intent data = result.getData();                    doSomeOperations();                }            }        });public void openSomeActivityForResult() {    Intent intent = new Intent(this, SomeActivity.class);    someActivityResultLauncher.launch(intent);}

参考

https://segmentfault.com/a/11...
https://developer.android.com...

更多相关文章

  1. Fuel:Kotlin / Android最简单的HTTP网络库
  2. Flutter Android启动源码分析(一)
  3. Android(安卓)MTP之服务端UsbService启动
  4. Activity的四种启动方式
  5. android 获取sim卡运营商信息
  6. Android(安卓)Studio ADB响应失败解决方法
  7. (备忘)Android(安卓)app中调用启动其他应用(系统应用和第三方应用)
  8. 《Android》Lesson09-Acitivity的四种启动模式
  9. android recovery 模式启动进入流程

随机推荐

  1. Android(安卓)透明状态栏
  2. 回弹效果listview
  3. Android图片预览效果,支持缩放、平移切换
  4. AsyncTask 和Timer同时使用
  5. 解析json格式数据
  6. python+appium+unittest+HtmlTestRunner
  7. FragmentActivity和Activity的区别及何时
  8. 简单实现android短信发送器
  9. Android数组显示
  10. Android:AsyncTask 模拟下载