AndroidResultContracts.TakePicture() 返回 bool 值而不是位图

标签 android image android-activity onactivityresult contract

合约已更改返回Boolean而不是 Bitmap从 androidx.activity 版本 1.2.0-alpha05 开始。如何使用 Boolean由内置 AndroidResultContracts.TakePicture() 返回契约(Contract)访问和显示用户刚刚拍摄的照片?

最佳答案

我在用

    implementation 'androidx.activity:activity-ktx:1.2.0-alpha07'
    implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha07'
这是我的完整示例代码,展示了如何使用内置的 Android Result Contract 从您的应用程序中获取照片并将其显示在 ImageView 中。
注意:我的解决方案使用 View BindingMainActivity的布局 XML 包括 (1) 定义 onTakePhotoClick 的按钮作为 onClick事件和 (2) 和 ImageView 显示拍摄的照片。
        <Button
            android:id="@+id/take_photo_button"
            style="@style/Button"
            android:drawableStart="@drawable/ic_camera_on"
            android:onClick="onTakePhotoClick"
            android:text="@string/button_take_photo"
            app:layout_constraintTop_toBottomOf="@id/request_all_button" />

        ...

        <ImageView
            android:id="@+id/photo_preview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@id/take_video_button" />
在我的 MainActivity我做了以下事情:
  • 定义 imageUri: Uri?将设置为 TakePicture() 拍摄的图像的 uri契约(Contract)。
  • 已实现 onTakePhotoClick()在启动 TakePicture() 之前检查必要的相机权限契约(Contract)。
  • 定义 takePictureRegistration: ActivityResultLauncher这实际上将启动在设备上拍照的请求。当isSuccess返回为 true然后我知道imageUri我之前定义的现在引用了我刚拍的照片。
  • 定义了 takePicture: Runnable只是为了代码重用。请注意,第二个 String传递给 FileProvider.getUriForFile(context, authority, file) 的参数方法需要匹配 authorities提供给 <provider> 的属性在您应用的 AndroidManifest.xml .
  • 为了完全透明,我还添加了显示我如何使用 ActivityResultContracts.RequestPermission() 的代码。请求用户访问相机的运行时权限。
  •     private var imageUri: Uri? = null
    
        /**
         * Function for onClick from XML
         *
         * Check if camera permission is granted, and if not, request it
         * Once permission granted, launches camera to take photo
         */
        fun onTakePhotoClick(view: View) {
            if (!checkPermission(Manifest.permission.CAMERA)) {
                // request camera permission first
                onRequestCameraClick(callback = takePicture)
            } else {
                takePicture.run()
            }
        }
    
        private val takePicture: Runnable = Runnable {
            ImageUtils.createImageFile(applicationContext)?.also {
                imageUri = FileProvider.getUriForFile(
                    applicationContext,
                    BuildConfig.APPLICATION_ID + ".fileprovider",
                    it
                )
                takePictureRegistration.launch(imageUri)
            }
        }
    
        private val takePictureRegistration =
            registerForActivityResult(ActivityResultContracts.TakePicture()) { isSuccess ->
                if (isSuccess) {
                    mBinding.photoPreview.setImageURI(imageUri)
                }
            }
    
        /**
         * Function for onClick from XML
         *
         * Launches permission request for camera
         */
        fun onRequestCameraClick(view: View? = null, callback: Runnable? = null) {
            registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
                // update image
                mBinding.iconCameraPermission.isEnabled = isGranted
    
                val message = if (isGranted) {
                    "Camera permission has been granted!"
                } else {
                    "Camera permission denied! :("
                }
    
                Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    
                if (isGranted) {
                    callback?.run()
                }
            }.launch(Manifest.permission.CAMERA)
        }
    
    
    为了完全透明,ImageUtils实用程序类具有 createImageFile()方法定义如下并返回 File?当给定上下文时。请注意,我使用外部文件目录作为 FileProvider 的存储目录。
    object ImageUtils {
        lateinit var currentPhotoPath: String
    
        @Throws(IOException::class)
        fun createImageFile(context: Context): File? {
            // Create an image file name
            val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
            val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
            return File.createTempFile(
                "JPEG_${timeStamp}_", /* prefix */
                ".jpg", /* suffix */
                storageDir /* directory */
            ).apply {
                // Save a file: path for use with ACTION_VIEW intents
                currentPhotoPath = absolutePath
            }
        }
    }
    
    不要忘记添加 uses-permission , uses-featureprovider标记到 AndroidManifest .
    还要确保 authorities提供给 <provider> 的属性匹配传递给 FileProvider.getUriForFile(context, authority, file) 的第二个字符串参数方法。在我的示例中,我已将我的权限设为包名 +“.fileprovider”。阅读更多关于 FileProvider from Google's documentation .
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.captech.android_activity_results">
    
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
        <uses-feature android:name="android.hardware.camera" />
    
        <application
            ...
    
            <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="com.captech.android_activity_results.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>
        </application>
    </manifest>
    
    我的 res/xml/file_paths如下图所示。因为我用的是getExternalFilesDir() , 我正在使用 <external-files-path> XML 中的标签。
    注意:如果您不使用外部文件目录,您可能需要查找要在 XML 标记中指定的 FileProvider 存储目录 here .
    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-files-path
            name="my_images"
            path="/" />
    </paths>
    
    结果将显示 imageUri在 ImageView 中:
    The image that was just taken by the device camera is being displayed in an ImageView in the application

    关于AndroidResultContracts.TakePicture() 返回 bool 值而不是位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63403425/

    相关文章:

    java - Android Webview 内容在使用透明背景时重叠

    java - 如何使用字符串的内容命名调用方法

    android - 如何使用 getActivity() 返回 fragment 类中的上下文?

    android - 我们可以在 Android 中调整按钮的边框吗?

    C#打印像素值

    android - 何时实际使用 savedInstanceState 包?

    android - 为什么单例类在 Activity 退出后仍然存在?

    Android Table Layout with Scrollview 不适合 parent 的宽度

    c# - 访问rest web服务时,如何在android中使用HttpPost和NameValuePair传递参数值?

    css - 图像大小调整的 CCS 问题 - Woocommerce 商店