博客
关于我
Android onActivityResult的替代方法—registerForActivityResult
阅读量:370 次
发布时间:2019-03-05

本文共 7802 字,大约阅读时间需要 26 分钟。

registerForActivityResult的使用指南

随着Android开发的进步,Google推出了Fragment-KTX库,该库引入了一系列与Activity相关的新API。最值得注意的是,startActivityForResult()onActivityResult()requestPermissions()等方法已被标记为过时,取而代之的是全新的registerForActivityResult()方法。这一变化为开发者提供了更灵活的方式来管理活动与结果的传递。本文将详细介绍如何使用这些新API。


1. 基本用法

registerForActivityResult()方法的核心作用是注册一个ActivityResultLauncher,这使得开发者能够在需要时启动活动,并通过回调接收结果。以下是基本使用方法:

registerForActivityResult(    ActivityResultContracts.StartActivityForResult()) { it ->    val data = it.data    val resultCode = it.resultCode}.launch(Intent(context, BActivity::class.java))

在上述代码中,ActivityResultContracts.StartActivityForResult()指定了需要处理的活动结果类型。launch()方法接受一个Intent对象,表示要启动的目标活动。注册好的ActivityResultLauncher在调用launch()时会启动目标活动,并在活动完成后通过回调接收结果。

需要注意的是,ActivityResultLauncher必须在onCreate()方法或Fragment的onCreate()onAttach()中先注册,然后在需要调用的地方调用launch()方法。以下是一个完整的示例:

private lateinit var activityResultLauncher: ActivityResultLauncheroverride fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_main)    activityResultLauncher = registerForActivityResult(        ActivityResultContracts.StartActivityForResult()    ) { it ->        val data = it.data        val resultCode = it.resultCode    }    val textView = findViewById(R.id.textView)    textView.setOnClickListener {        activityResultLauncher.launch(Intent(this, BActivity::class.java))    }}

2. 调用联系人列表

registerForActivityResult()还可以用于调用联系人列表。以下是获取联系人信息的具体实现:

registerForActivityResult(    ActivityResultContracts.PickContact()) { it ->    if (it != null) {        val cursor = contentResolver.query(            it,            null,            null,            null,            null        )        cursor?.run {            if (cursor.moveToFirst()) {                val name = cursor.getString(                    cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)                )                val hasPhone = cursor.getString(                    cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)                )                if (hasPhone == "1") {                    // 处理联系人信息                }            }        }    }}.launch(null)

在上述代码中,ActivityResultContracts.PickContact()用于选择联系人,launch(null)方法会启动联系人选择器。通过contentResolver.query()可以获取联系人信息,并根据需求进行处理。


3. 获取敏感权限

registerForActivityResult()还可用于请求应用程序权限。以下是获取单个权限和多个权限的实现方法:

3.1 获取单个权限

registerForActivityResult(    ActivityResultContracts.RequestPermission()) { it ->    if (it) {        // 用户同意了该权限    } else {        // 用户拒绝了该权限    }}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)

3.2 获取多个权限

registerForActivityResult(    ActivityResultContracts.RequestMultiplePermissions()) { it ->    val grantedList = it.filterValues { it }.mapNotNull { it.key }    val allGranted = grantedList.size == it.size    val list = (it - grantedList).map { it.key }    val deniedList = list.filter { ActivityCompat.shouldShowRequestPermissionRationale(this, it) }    val alwaysDeniedList = list - deniedList}.launch(    arrayOf(        Manifest.permission.WRITE_EXTERNAL_STORAGE,        Manifest.permission.READ_EXTERNAL_STORAGE    ))

4. 调用文件选择器

registerForActivityResult()可以用于调用文件选择器,获取指定类型的文件。以下是常用的实现方法:

4.1 使用GetContent()合约

registerForActivityResult(    ActivityResultContracts.GetContent()).launch("text/plain")

4.2 使用OpenDocument()合约

registerForActivityResult(    ActivityResultContracts.OpenDocument()).launch(arrayOf("image/*", "text/plain"))

如果需要选择多种文件类型,可以使用OpenDocument()合约。以下是常用的文件 MIME 类型对应关系:

文件扩展名 MIME 类型
.jpg、.jpeg image/jpeg
.png image/png
.webp image/webp
.bmp image/bmp
.gif image/gif
.xls、.xlsx application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.doc、.docx application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document
.pdf application/pdf
.pps、.ppt application/vnd.ms-powerpoint
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.apk application/vnd.android.package-archive
.js application/x-javascript
.jar application/java-archive
.bin、.class、.exe、.rar application/octet-stream
.tar application/x-tar
.tgz application/x-compressed
.zip application/x-zip-compressed
.html、.htm text/html
.txt text/plain
.wav audio/x-wav
.wma audio/x-ms-wma
.wmv audio/x-ms-wmv
.m3u audio/x-mpegurl
.m4a、.m4b、.m4p audio/mp4a-latm
.mp2、.mp3 audio/x-mpeg
.mpga audio/mpeg
.ogg audio/ogg
.3gp video/3gpp
.asf video/x-ms-asf
.avi video/x-msvideo
.m4u video/vnd.mpegurl
.m4v video/x-m4v
.mov video/quicktime
.mp4、.mpg4 video/mp4
.mpe、.mpeg、.mpg video/mpeg
.webp video/webp

5. 调用相机

registerForActivityResult()还可以用于调用相机,获取图片文件。以下是常用的实现方法:

// 需要WRITE_EXTERNAL_STORAGE权限val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {    val values = ContentValues()    values.put(MediaStore.MediaColumns.DISPLAY_NAME, "图片名称.jpg")    values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)    contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)} else {    FileProvider.getUriForFile(        this,        BuildConfig.authorities,        File(externalCacheDir!!.absolutePath + "图片名称.jpg")    )}registerForActivityResult(    ActivityResultContracts.TakePicture()) { it ->    if (it) {        Glide.with(this).load(uri).into(binding.imageView)    }}.launch(uri)

或者使用以下方式,直接返回Bitmap图片:

registerForActivityResult(    ActivityResultContracts.TakePicturePreview()) { it ->    Glide.with(this).load(it).into(binding.imageView)}.launch(null)

6. 自定义ActivityResultContract

除了使用官方提供的ActivityResultContract,开发者还可以实现自定义ActivityResultContract以满足特定需求。以下是一个裁剪图片的ActivityResultContract示例:

class CropImageContent :    ActivityResultContract
{ override fun createIntent(context: Context, input: CropImageResult): Intent { val intent = Intent("com.android.camera.action.CROP") val imageName = "${input.imageName}.jpg" val outUri = Uri.fromFile(getClipImage(context, imageName)) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.putExtra("noFaceDetection", true) intent.setDataAndType(input.uri, "image/*") intent.putExtra("crop", true) intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()) intent.putExtra("return-data", false) intent.putExtra(MediaStore.EXTRA_OUTPUT, outUri) if (input.outputX != 0 && input.outputY != 0) { intent.putExtra("outputX", input.outputX) intent.putExtra("outputY", input.outputY) } if (input.aspectX != 0 && input.aspectY != 0) { if (input.aspectY == input.aspectX && Build.MANUFACTURER == "HUAWEI") { intent.putExtra("aspectX", 9999) intent.putExtra("aspectY", 9998) } else { intent.putExtra("aspectX", input.aspectX) intent.putExtra("aspectY", input.aspectY) } } return intent } override fun parseResult(resultCode: Int, intent: Intent?): Uri? { if (resultCode == -1) { return outUri } else { return null } } private fun getClipImage(context: Context, clipImageName: String): File { val file = File(externalCacheDir!!.absolutePath + "图片名称.jpg") return file }}class CropImageResult( val uri: Uri, val aspectX: Int = 0, val aspectY: Int = 0, @IntRange(from = 0, to = 1080) val outputX: Int = 0, @IntRange(from = 0, to = 1080) val outputY: Int = 0, val imageName: String = "temp_crop_image") { // 其他字段和方法}

7. 使用示例

以下是一个使用示例,展示如何裁剪图片并加载到ImageView中:

// 裁剪图片private fun crop(uri: Uri) {    registerForActivityResult(CropImageContent()) {        Glide.with(this).load(it.toFile).into(binding.ivImage)    }.launch(CropImageResult(uri))}

通过以上方法,开发者可以充分利用registerForActivityResult()API,简化Activity与结果管理的代码,提升开发效率。

转载地址:http://vyig.baihongyu.com/

你可能感兴趣的文章
multipart/form-data与application/octet-stream的区别、application/x-www-form-urlencoded
查看>>
mysql cmake 报错,MySQL云服务器应用及cmake报错解决办法
查看>>
Multiple websites on single instance of IIS
查看>>
mysql CONCAT()函数拼接有NULL
查看>>
multiprocessing.Manager 嵌套共享对象不适用于队列
查看>>
multiprocessing.pool.map 和带有两个参数的函数
查看>>
MYSQL CONCAT函数
查看>>
multiprocessing.Pool:map_async 和 imap 有什么区别?
查看>>
MySQL Connector/Net 句柄泄露
查看>>
multiprocessor(中)
查看>>
mysql CPU使用率过高的一次处理经历
查看>>
Multisim中555定时器使用技巧
查看>>
MySQL CRUD 数据表基础操作实战
查看>>
multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
查看>>
mysql csv import meets charset
查看>>
multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
查看>>
MySQL DBA 数据库优化策略
查看>>
multi_index_container
查看>>
MySQL DBA 进阶知识详解
查看>>
Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
查看>>