Android Activity Result API (二) :拍照与选择照片

语言: CN / TW / HK

在之前的文章中介绍过如何使用Activity Result API替换onActivityResult方法以及如何进行权限申请。本篇文章介绍下如何使用Activity Result API 实现拍照以及选择手机中的图片。

实现拍照

在之前的文章中提到过,ActivityResutlContract已经有一些官方实现好的默认合约,其中就包含了两个拍照相关的合约TakePictureTakePicturePreview,二者都可以实现拍照功能。

TakePicture

TakePicture合约需要传入保存照片文件的Uri,因此需要使用FileProvider,通过TakePicture合约实现拍照代码如下:

``` //在res文件夹下新建xml资源文件夹,并新建file_path.xml资源文件

//在Manifest中配置FileProvider

<application>

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_path" />
    </provider>
</application>

class PhotoActivity : AppCompatActivity() {

private lateinit var binding: LayoutPhotoActivityBinding

private var photoUri: Uri? = null

private val takePicture =
    registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
        if (success) {
            photoUri?.let {
                binding.ivPhoto.setImageURI(it)
            }
        }
    }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)

    photoUri = getPhotoFileUri()

    binding.btnTakePhoto.setOnClickListener {
        takePicture.launch(photoUri)
    }
}

//获取保存照片的Uri
private fun getPhotoFileUri(): Uri? {
    val storageFile: File? =
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            externalCacheDir
        } else {
            cacheDir
        }

    val photoFile = File.createTempFile("tmp_image_file", ".png", storageFile).apply {
        createNewFile()
        deleteOnExit()
    }
    val fileProviderUri = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", photoFile)
    return fileProviderUri
}

}

``` 效果图:

TakePicture_.gif

TakePicturePreview

通过TakePicturePreview合约实现拍照代码如下:

``` class PhotoActivity : AppCompatActivity() {

private lateinit var binding: LayoutPhotoActivityBinding

private val takePicturePreview =
    registerForActivityResult(ActivityResultContracts.TakePicturePreview()) { photoPreview ->
        //该合约返回的是Bitmap,如需保存要进行额外的处理
        binding.ivPhoto.setImageBitmap(photoPreview)
    }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)

    binding.btnTakePhotoPreview.setOnClickListener {
        takePicturePreview.launch(null)
    }
}

}

``` 效果图:

TakePicturePreview_.gif

实现选择图片

ActivityResutlContract官方实现好的默认合约中,GetContent可以用来获取手机中的资源,因此可以使用这个合约来获取手机中的图片。代码如下:

``` class PhotoActivity : AppCompatActivity() {

private lateinit var binding: LayoutPhotoActivityBinding

private val selectPhoto =
    registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
        binding.ivPhoto.setImageURI(uri)
    }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)

    binding.btnSelectPhoto.setOnClickListener {
        //传入的参数就是你想要选择的资源类型
        selectPhoto.launch("image/*")
    }
}

} ```

效果图:

GetContent_.gif