AndroidResultContracts.TakePicture()返回布尔值而不是位图 [英] AndroidResultContracts.TakePicture() returns Boolean instead of Bitmap

查看:182
本文介绍了AndroidResultContracts.TakePicture()返回布尔值而不是位图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

合同已更改为从androidx.activity版本1.2.0-alpha05开始返回 Boolean 而不是 Bitmap .如何使用内置

The contract has been changed to return Boolean instead of Bitmap starting in androidx.activity version 1.2.0-alpha05. How can I use the Boolean returned by the built in AndroidResultContracts.TakePicture() contract to access and display the photo just taken by the user?

解决方案

I am using

    implementation 'androidx.activity:activity-ktx:1.2.0-alpha07'
    implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha07'

Here's my full sample code showing how to use the built-in Android Result Contract to take a photo from your application and display it in an ImageView.

Note: My solution uses View Binding

MainActivity's layout XML included (1) a button defining onTakePhotoClick as the onClick event and (2) and ImageView to display the photo taken.

        <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" />

In my MainActivity I have done the following:

  1. Defined imageUri: Uri? which will be set to the uri of the image taken by the TakePicture() contract.
  2. Implemented onTakePhotoClick() to check for the necessary camera permissions before launching the TakePicture() contract.
  3. Defined takePictureRegistration: ActivityResultLauncher which will actually launch the request to take a photo on the device. When isSuccess is returned as true then I know the imageUri I previously defined now references the photo I just took.
  4. Defined a takePicture: Runnable simply for code reuse. Note that the 2nd String parameter passed to the FileProvider.getUriForFile(context, authority, file) method will need to match the authorities attribute provided to the <provider> in your app's AndroidManifest.xml.
  5. For full transparency, I have also added the code showing how I use the ActivityResultContracts.RequestPermission() to request the user for runtime permissions to access the camera.

    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)
    }

For full transparency the ImageUtils utility class has the createImageFile() method defined as follows and returns a File? when given context. Note that I am using the external files directory as the storage directory for my 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
        }
    }
}

Don't forget to add the uses-permission, uses-feature and provider tags to the AndroidManifest.

Also make sure the authorities attribute provided to the <provider> matches the 2nd String parameter passed to FileProvider.getUriForFile(context, authority, file) method. In my example, I have made my authority the package name + ".fileprovider". Read more about 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>

My res/xml/file_paths is shown below. Because I am using getExternalFilesDir(), I am using the <external-files-path> tags in the XML.

Note: If you are NOT using the external files directory, you may want to look up which FileProvider storage directory you want to specify in your XML tags here.

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-files-path
        name="my_images"
        path="/" />
</paths>

The result would display the imageUri in the ImageView:

这篇关于AndroidResultContracts.TakePicture()返回布尔值而不是位图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆