自从Google官方发布Jetpack以来,我们Android开发的很多开发习惯都发生了巨大的变化,最近又双叒叕在实现更换头像的功能。发现以前startActivityForResult + onActivityResult 那一套做法又有了新的实现方式。略微找了下相关资料,动手实现了出来,发现代码能够更简洁也更优雅了,感觉收获了一点小惊喜。所以这里给大家分享一下。
以前请求权限以及startActivityForResult,都免不了要实现onActivityResult,代码分离,逻辑不连贯,还要生命一连串code,一个不留神就功能对应不上,浪费时间排查。现在使用registerForActivityResult + ActivityResultContract来实现就更加方便了。
官方已经帮我们封装好了一部分可以直接使用,列在下面就不多做介绍了:
ActivityResultContracts.CaptureVideo, ActivityResultContracts.Createdocument, ActivityResultContracts.GetContent, ActivityResultContracts.GetMultipleContents, ActivityResultContracts.OpendocumentTree, ActivityResultContracts.Opendocument, ActivityResultContracts.OpenMultipledocuments, ActivityResultContracts.PickContact, ActivityResultContracts.RequestMultiplePermissions, ActivityResultContracts.RequestPermission, ActivityResultContracts.StartActivityForResult, ActivityResultContracts.StartIntentSenderForResult, ActivityResultContracts.TakePicturePreview, ActivityResultContracts.TakePicture, ActivityResultContracts.TakeVideo, ActivityResultContracts.WatchFaceEditorContract
这里主要介绍自定义Contract来实现打开相机拍照、打开相册选择照片,然后进行裁剪是如何实现的。
一、首先,先继承ActivityResultContract实现自定义的Contract,如下:
SelectPhotoContract:
class SelectPhotoContract : ActivityResultContract() { companion object { private const val TAG = "SelectPhotoContract" } override fun createIntent(context: Context, input: Unit?): Intent { return Intent(Intent.ACTION_PICK).setType("image class TakePhotoContract : ActivityResultContract () { companion object { private const val TAG = "TakePhotoContract" } private var uri: Uri? = null override fun createIntent(context: Context, input: Unit?): Intent { val mimeType = "image/jpeg" val fileName = "IMG_${System.currentTimeMillis()}.jpg" uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10 及以上获取图片uri val values = contentValuesOf( Pair(MediaStore.MediaColumns.DISPLAY_NAME, fileName), Pair(MediaStore.MediaColumns.MIME_TYPE, mimeType), Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM) ) context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) } else { // Android 9 及以下获取图片uri FileProvider.getUriForFile( context, "${context.packageName}.provider", File(context.externalCacheDir, "/$fileName") ) } return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri) } override fun parseResult(resultCode: Int, intent: Intent?): Uri? { Logger.d(TAG, "Take photo, resultCode: $resultCode, uri: $uri") if (resultCode == Activity.RESULT_OK) return uri return null } }
CropPhotoContract:
class CropPhotoContract : ActivityResultContract() { companion object { private const val TAG = "CropPhotoContract" } private var output: CropOutput? = null override fun createIntent(context: Context, input: Uri): Intent { // 获取输入图片uri的媒体类型 val mimeType = context.contentResolver.getType(input) // 创建新的图片名称 val fileName = "IMG_${System.currentTimeMillis()}.${ MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) }" val outputUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10 及以上获取图片uri val values = contentValuesOf( Pair(MediaStore.MediaColumns.DISPLAY_NAME, fileName), Pair(MediaStore.MediaColumns.MIME_TYPE, mimeType), Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM) ) context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) } else { Uri.fromFile(File(context.externalCacheDir!!.absolutePath, fileName)) } output = CropOutput(outputUri!!, fileName) return Intent("com.android.camera.action.CROP") .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) .setDataAndType(input, "image private val takePhotoLauncher = (this as ComponentActivity).registerForActivityResult(TakePhotoContract()) { uri -> uri?.let { cropPhotoLauncher.launch(it) } } private val selectPhotoLauncher = (this as ComponentActivity).registerForActivityResult(SelectPhotoContract()) { uri -> uri?.let { cropPhotoLauncher.launch(it) } } private val cropPhotoLauncher = (this as ComponentActivity).registerForActivityResult(CropPhotoContract()) { output -> output?.let { Logger.d(TAG, "裁剪完成,开始上传头像到服务器, output: $it") // 上传头像 showLoading(getString(R.string.base_uploading)) mViewModel.fetchUpload(ContentUriRequestBody(contentResolver, it.uri), it.fileName) } }
三、调用:
// 打开相机 takePhotoLauncher.launch(null) // 打开相册 selectPhotoLauncher.launch(null)
OVER
很简单,不是么!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)