本文共 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/