Android使用registerForActivityResult()打开系统相册或相机获取图像
- 人工智能
- 2025-08-17 08:09:02

一、简介
当使用了 AndroidX 后,发现 `startActivityForResult()` 标记为过时了,而是推荐我们使用 `registerForActivityResult()` 函数。
`registerForActivityResult()` 函数是 Android 中用于启动 Activity 结果回调的新方式。这个函数的目的是简化在 Activity 和 Fragment 之间进行启动其他 Activity 并接收结果的过程,取代了传统的 `startActivityForResult()` 和 `onActivityResult()` 方法。
使用 `registerForActivityResult()` 函数,您可以更容易地管理 Activity 结果的处理,使代码更清晰和模块化。
AndroidX 介绍:
AndroidX 是 Android 中的一个开发库,旨在简化 Android 应用程序的开发和维护。AndroidX 提供了一组替代 Android Support Library 的库,它们包括了新的功能、改进的性能和更好的兼容性,以便开发人员更轻松地构建现代化、高质量的 Android 应用程序。
主要包括:
新功能和改进: AndroidX 引入了许多新的功能和改进,包括更好的 Jetpack 组件、性能优化、Kotlin 支持、Android 架构组件等,以提高开发效率和用户体验。向后兼容性: AndroidX 专注于提供向后兼容性,以确保应用程序在不同 Android 版本上能够稳定运行。这意味着即使您的应用使用了 AndroidX 库,也可以在较旧的 Android 版本上运行。Jetpack 组件: AndroidX 包括了 Android Jetpack 组件,这是一组库和工具,旨在简化 Android 应用程序的常见开发任务,例如导航、数据存储、UI 构建、生命周期管理等。Jetpack 组件的目标是提高应用程序的可维护性、稳定性和性能。 二、打开相册获取图像 1. 代码示例 public class MainActivity extends AppCompatActivity { private ActivityResultLauncher<String> mGalleryLauncher; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 需要事先注册 mGalleryLauncher = registerForActivityResult( // 获取内容,回调函数的参数将是一个URI new ActivityResultContracts.GetContent(), // 回调函数 this::handleGalleryResult); } private void openGallery() { if (mGalleryLauncher != null) { // launch的输入参数是泛型,对应ActivityResultLauncher<String> mGalleryLauncher.launch("image/*"); } } private void handleGalleryResult(Uri imageUri) { if (imageUri != null) { try { Bitmap selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri); int rotation = ImageUtil.getRotation(this, imageUri); Bitmap rotatedBitmap = ImageUtil.rotateBitmap(selectedBitmap, rotation); // 后续处理逻辑 } catch (Exception e) { e.printStackTrace(); } } } } 2. ImageUtil部分函数 public static Bitmap rotateBitmap(Bitmap bitmap, int rotation) { if (rotation == 0) { return bitmap; } return rotateResizeBitmap(bitmap, rotation, 1f); } public static Bitmap rotateResizeBitmap(Bitmap source, float angle, float scale) { Matrix matrix = new Matrix(); matrix.postRotate(angle); if (scale != 1f) { matrix.setScale(scale, scale); } return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } public static int getRotation(Context context, Uri photoUri) { if (photoUri == null) { return 0; } ExifInterface ei; try { InputStream inputStream = context.getContentResolver().openInputStream(photoUri); ei = new ExifInterface(inputStream); } catch (IOException e) { return 0; } int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: return 90; case ExifInterface.ORIENTATION_ROTATE_180: return 180; case ExifInterface.ORIENTATION_ROTATE_270: return 270; default: return 0; } } 三、打开相机获取图像因为使用的是系统相机应用,所以也不需要额外申请相机权限了。
1. 代码示例 public class MainActivity extends AppCompatActivity { private ActivityResultLauncher<Intent> mCameraLauncher; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 需要事先注册 mCameraLauncher = registerForActivityResult( // 回调函数的参数将是一个ActivityResult new ActivityResultContracts.StartActivityForResult(), // 回调函数 this::handleCameraResult); } private void openCamera() { if (mCameraLauncher != null) { // launch的输入参数是泛型,对应ActivityResultLauncher<Intent> Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 确保有相机应用可用 if (takePictureIntent.resolveActivity(getPackageManager()) != null) { mCameraLauncher.launch(takePictureIntent); } } } private void handleCameraResult(ActivityResult result) { if (result.getResultCode() == RESULT_OK) { Intent data = result.getData(); if (data != null) { Bundle extras = data.getExtras(); if (extras != null) { Uri uri = data.getData(); Bitmap imageBitmap = (Bitmap) extras.get("data"); // 后续处理逻辑 } } } } }注意:
由于Bundle本身能够携带的数据大小限制,上面这种方式获取的相机图像分辨率通常很低。如果希望能够获取较大分辨率的图像,则可以先将相机图像保存到本地,再通过文件路径加载。具体方式如下:
2. 修改openCamera()在打开相机的Intent中添加一个文件输出的Uri,告诉相机需要保存到指定位置。
private String mPhotoPath; // 用于存储文件保存的路径 private void openCamera() { if (mCameraLauncher != null) { // launch的输入参数是泛型,对应ActivityResultLauncher<Intent> Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 确保有相机应用可用 if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // 创建一个用于存储拍照结果的文件 File photoFile = ImageUtil.createImageFile(this); mPhotoPath = photoFile.getAbsolutePath(); Uri photoUri = FileProvider.getUriForFile(this, "com.afei.demo.provider", // 对应 AndroidManifest.xml 中的声明 photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); mCameraLauncher.launch(takePictureIntent); } } } 3. ImageUtil.createImageFile() 代码创建一个可写的文件即可。
public static File createImageFile(Context context) { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date(System.currentTimeMillis())); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (!storageDir.exists()) { storageDir.mkdirs(); } File imageFile = null; try { imageFile = File.createTempFile( imageFileName, /* 文件名 */ ".jpg", /* 文件扩展名 */ storageDir /* 存储目录 */ ); imageFile.setWritable(true); } catch (IOException e) { e.printStackTrace(); } return imageFile; } 4. 自定义的FileProvider上述代码中还使用到了一个 `FileProvider.getUriForFile()` 方法,作为四大组件之一,也是需要在 AndroidManifest.xml 文件中声明和使用的。
a. AndroidManifest.xml 文件中 <application> ... <provider android:name="androidx.core.content.FileProvider" android:authorities="com.afei.demo.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>authorities 通常可以用 `包名+.provider`。
b. xml/file_paths 文件在 res 文件夹下面创建一个 xml 子文件夹,并新建 file_paths.xml 文件(文件名可以修改,和AndroidManifest.xml中对应上就行),内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android /apk/res/android"> <external-path name="my_images" path="." /> </paths>关于FileProvider的使用这里不过多介绍了,不清楚的可以查阅其他资料。
5. 修改 handleCameraResult(ActivityResult result)这里就不再需要通过 ActivityResult 获取数据了,而是从之前存储的 `mPhotoPath` 中获取。
private void handleCameraResult(ActivityResult result) { if (result.getResultCode() == RESULT_OK) { Bitmap bitmap = BitmapFactory.decodeFile(mPhotoPath); // 后续处理逻辑 } }Android使用registerForActivityResult()打开系统相册或相机获取图像由讯客互联人工智能栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Android使用registerForActivityResult()打开系统相册或相机获取图像”
上一篇
Spring5应用之事务处理
下一篇
MavenEclipse