本文共 7802 字,大约阅读时间需要 26 分钟。
随着Android开发的进步,Google推出了Fragment-KTX库,该库引入了一系列与Activity相关的新API。最值得注意的是,startActivityForResult()
、onActivityResult()
、requestPermissions()
等方法已被标记为过时,取而代之的是全新的registerForActivityResult()
方法。这一变化为开发者提供了更灵活的方式来管理活动与结果的传递。本文将详细介绍如何使用这些新API。
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)) }}
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()
可以获取联系人信息,并根据需求进行处理。
registerForActivityResult()
还可用于请求应用程序权限。以下是获取单个权限和多个权限的实现方法:
registerForActivityResult( ActivityResultContracts.RequestPermission()) { it -> if (it) { // 用户同意了该权限 } else { // 用户拒绝了该权限 }}.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
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 ))
registerForActivityResult()
可以用于调用文件选择器,获取指定类型的文件。以下是常用的实现方法:
GetContent()
合约registerForActivityResult( ActivityResultContracts.GetContent()).launch("text/plain")
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 |
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 |
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)
除了使用官方提供的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") { // 其他字段和方法}
以下是一个使用示例,展示如何裁剪图片并加载到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/