添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
·  阅读

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

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

TakePicture

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

//在res文件夹下新建xml资源文件夹,并新建file_path.xml资源文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="images"
        path="." />
    <cache-path
        name="cache-path"
        path="." />
    <external-path
        name="external_storage_root"
        path="." />
    <external-cache-path
        name="external_cache_path"
        path="." />
</paths>
//在Manifest中配置FileProvider
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <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>
</manifest>
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

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)

实现选择图片

ActivityResutlContract官方实现好的默认合约中,GetContentGetMultipleContents可以用来获取手机中的资源,因此可以使用这两个合约来获取手机中的图片。

GetContent

通过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/*")

GetMultipleContents

通过GetMultipleContents合约实现选择多张照片代码如下:

class PhotoActivity : AppCompatActivity() {
    private lateinit var binding: LayoutPhotoActivityBinding
    private val selectMultiplePhoto =
        registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { uriList ->
            if (uriList.size > 1) {
                binding.ivPhoto.setImageURI(uriList[0])
                binding.ivPhoto1.setImageURI(uriList[1])
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_photo_activity)
        binding.btnSelectMultiplePhoto.setOnClickListener {
            //传入的参数就是你想要选择的资源类型
            selectMultiplePhoto.launch("image/*")

1649486279509549_.gif

分类:
Android
  •