API 过时 onActivityResult 替换 Activity Results API

984 阅读3分钟

新的Activity Results API

预定义了很多Contract,它们都定义在类ActivityResultContracts

StartActivityForResult()   
RequestMultiplePermissions()  
RequestPermission()  
TakePicturePreview()  
TakePicture()  
TakeVideo()  
PickContact()  
CreateDocument()  
OpenDocumentTree()  
OpenMultipleDocuments()  
OpenDocument()  
GetMultipleContents()  
GetContent()
  • 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中,除了StartActivityForResultRequestMultiplePermissions之外,基本都是处理的与其他APP交互,返回数据的场景,比如,拍照,选择图片,选择联系人,打开文档等。

使用样例

    1. 注册协议,获取ActivityResultLauncher
private val myActivityLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ activityResult ->    
        if(activityResult.resultCode == Activity.RESULT_OK){  
            val result = activityResult.data?.getStringExtra("result")  
            Toast.makeText(applicationContext,result,Toast.LENGTH_SHORT).show()  
            textView.text = "回传数据:$result"  
        }  
    }
    1. 构造需要传递的数据,启动页面跳转
button.setOnClickListener {  
        val  intent = Intent(this,SecondActivity::class.java).apply {  
             putExtra("name","Hello,技术最TOP")  
        }  
        myActivityLauncher.launch(intent)  
}
    1. 获取权限样例代码
request_permission.setOnClickListener {  
    requestPermission.launch(permission.BLUETOOTH)  
}  
  
request_multiple_permission.setOnClickListener {  
    requestMultiplePermissions.launch(  
        arrayOf(  
            permission.BLUETOOTH,  
            permission.NFC,  
            permission.ACCESS_FINE_LOCATION  
        )  
    )  
}  
  
// 请求单个权限  
private val requestPermission =  
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->  
        // Do something if permission granted  
        if (isGranted) toast("Permission is granted")  
        else toast("Permission is denied")  
    }  
  
// 请求一组权限  
private val requestMultiplePermissions =  
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions : Map<String, Boolean> ->  
        // Do something if some permissions granted or denied  
        permissions.entries.forEach {  
            // Do checking here  
        }                                                                               
}

在非Activity/Fragment的类中接收Activity的结果

在Activity和Fragment中,我们能直接使用registerForActivityResultAPI ,那是因为ConponentActivityFragment基类实现了ActivityResultCaller 接口,在非Activity/Fragment中,如果我们想要接收Activity回传的数据,可以直接使用 ActivityResultRegistry 来实现。

比如,用一个单独的类来实现协议的注册和启动器的启动:

class MyLifecycleObserver(private val registry : ActivityResultRegistry)  
            : DefaultLifecycleObserver {  
        lateinit var getContent : ActivityResultLauncher<String>  
  
        fun onCreate(owner: LifecycleOwner) {  
            getContent = registry.register("key", owner, GetContent()) { uri ->  
                // Handle the returned Uri  
            }  
        }  
  
        fun selectImage() {  
            getContent("image/*")  
        }  
    }  
  
    class MyFragment : Fragment() {  
        lateinit var observer : MyLifecycleObserver  
  
        override fun onCreate(savedInstanceState: Bundle?) {  
            // ...  
  
            observer = MyLifecycleObserver(requireActivity().activityResultRegistry)  
            lifecycle.addObserver(observer)  
        }  
  
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {  
            val selectButton = view.findViewById<Button>(R.id.select_button)  
  
            selectButton.setOnClickListener {  
                // Open the activity to select an image  
                observer.selectImage()  
            }  
        }  
    }

示例中,我们在MyLifecycleObserver中实现协议注册和启动器启动,为什么要实现LifecycleObserver 呢?因为,使用生命周期组件,LifecycleOwner 会在 Lifecycle 被销毁时自动移除已注册的启动器。不过,如果 LifecycleOwner 不存在,则每个 ActivityResultLauncher 类都允许您手动调用 unregister() 作为替代。但在使用ActivityResultRegistry时,Google官方强烈建议我们使用可接受LifecycleOwner 作为参数的 API。

Activity和Fragment中为什么不需要手动调用unregister()呢?,因为ComponentActivity和Fragment已经实现了LifecycleObserver