Android Kotlin 打开相册选择图片(多选)

1. 核心代码

打开系统相册功能,本代码使用两种方式打开本地相册,startActivityForResult 已经废弃,可以使用新的方式。

package com.example.facedetectordemo

import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.facedetectordemo.databinding.ActivityMainBinding
import com.example.facedetectordemo.entity.FaceInfo
import android.Manifest;
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Activity
import android.content.ContentUris
import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.provider.DocumentsContract
import android.provider.MediaStore
import com.google.android.material.snackbar.Snackbar

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val CHOOSE_PHOTO = 1

    private val requestPermissionLauncher =
        registerForActivityResult(
            ActivityResultContracts.RequestPermission()
        ) { isGranted: Boolean ->
            if (isGranted) {
                Log.i("Permission: ", "Granted")
            } else {
                Log.i("Permission: ", "Denied")
            }
        }

    private val launcherActivity = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()) {
        val data = it.data
        if (it.resultCode == Activity.RESULT_OK) {
                // 判断手机系统版本号
                if (Build.VERSION.SDK_INT >= 19) {
                    // 4.4及以上系统使用这个方法处理图片
                    if (data != null) {
                        if(data.clipData != null) {
                            handleImageOnKitKat(data.clipData!!.getItemAt(0).uri)
                        } else if(data.data != null) {
                            handleImageOnKitKat(data.data!!)
                        }

                    }
                }

        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        // Example of a call to a native method
        binding.openGallery.setOnClickListener{
            val intent = Intent("android.intent.action.GET_CONTENT")
            intent.type = "image/*" // */
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            //startActivityForResult(intent, CHOOSE_PHOTO) // 打开相册, 废弃API
            launcherActivity.launch(intent)
        }

        val infos = getFaceInfoList()
        Log.d("zhouyong", "onCreate: size " + infos.size)

        requestPermission();
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            CHOOSE_PHOTO -> if (resultCode == Activity.RESULT_OK) {
                // 判断手机系统版本号
                if (Build.VERSION.SDK_INT >= 19) {
                    // 4.4及以上系统使用这个方法处理图片
                    if (data != null) {
                        if(data.clipData != null) {
                            handleImageOnKitKat(data.clipData!!.getItemAt(0).uri)
                        } else if(data.data != null) {
                            handleImageOnKitKat(data.data!!)
                        }

                    }
                } else {
                }
            }
            else -> {
            }
        }
    }

    @TargetApi(19)
    private fun handleImageOnKitKat(uri: Uri) {
        var imagePath: String? = null
        //val uri = data.data
        Log.d("TAG", "handleImageOnKitKat: uri is $uri")
        if (DocumentsContract.isDocumentUri(this, uri)) {
            // 如果是document类型的Uri,则通过document id处理
            val docId = DocumentsContract.getDocumentId(uri)
            if ("com.android.providers.media.documents" == uri!!.authority) {
                val id = docId.split(":".toRegex()).toTypedArray()[1] // 解析出数字格式的id
                val selection = MediaStore.Images.Media._ID + "=" + id
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection)
            } else if ("com.android.providers.downloads.documents" == uri.authority) {
                val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(docId))
                imagePath = getImagePath(contentUri, null)
            }
        } else if ("content".equals(uri!!.scheme, ignoreCase = true)) {
            // 如果是content类型的Uri,则使用普通方式处理
            imagePath = getImagePath(uri, null)
        } else if ("file".equals(uri.scheme, ignoreCase = true)) {
            // 如果是file类型的Uri,直接获取图片路径即可
            imagePath = uri.path
        }
        displayImage(imagePath) // 根据图片路径显示图片
    }

    @SuppressLint("Range")
    private fun getImagePath(uri: Uri?, selection: String?): String? {
        var path: String? = null
        // 通过Uri和selection来获取真实的图片路径
        val cursor = contentResolver.query(uri!!, null, selection, null, null)
        if (cursor != null) {
            if (cursor.moveToFirst()) {
                path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))
            }
            cursor.close()
        }
        return path
    }

    private fun displayImage(imagePath: String?) {
        if (imagePath != null) {
            val bitmap = BitmapFactory.decodeFile(imagePath)
            binding.imageView.setImageBitmap(bitmap)
        } else {
            //Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show()
        }
    }


    fun requestPermission() {
        when {
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED -> {
            }

            ActivityCompat.shouldShowRequestPermissionRationale(
                this,
                Manifest.permission.CAMERA
            ) -> {
                requestPermissionLauncher.launch(
                    Manifest.permission.CAMERA
                )
                requestPermissionLauncher.launch(
                    Manifest.permission.READ_EXTERNAL_STORAGE
                )
                requestPermissionLauncher.launch(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
            }

            else -> {
                requestPermissionLauncher.launch(
                    Manifest.permission.CAMERA
                )
                requestPermissionLauncher.launch(
                    Manifest.permission.READ_EXTERNAL_STORAGE
                )
                requestPermissionLauncher.launch(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
            }
        }
    }

    fun View.showSnackbar(
        view: View,
        msg: String,
        length: Int,
        actionMessage: CharSequence?,
        action: (View) -> Unit
    ) {
        val snackbar = Snackbar.make(view, msg, length)
        if (actionMessage != null) {
            snackbar.setAction(actionMessage) {
                action(this)
            }.show()
        } else {
            snackbar.show()
        }
    }

    /**
     * A native method that is implemented by the 'facedetectordemo' native library,
     * which is packaged with this application.
     */
    external fun stringFromJNI(): String

    external fun getFaceInfoList(): Array<FaceInfo>

    companion object {
        // Used to load the 'facedetectordemo' library on application startup.
        init {
            System.loadLibrary("facedetectordemo")
        }
    }
}

2. main_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/openGallery"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="212dp"
        android:text="打开相册"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:layout_constraintVertical_bias="1.0" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="96dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />

</androidx.constraintlayout.widget.ConstraintLayout>

相关推荐

  1. Android Kotlin 打开相册选择图片()

    2024-06-06 10:38:03       10 阅读
  2. el-table分页,一个其他类型相同的也选中

    2024-06-06 10:38:03       19 阅读
  3. 月份选择,数组去重

    2024-06-06 10:38:03       18 阅读
  4. el-tree实现、反、指定选择

    2024-06-06 10:38:03       30 阅读
  5. 通过按钮选择需要修改什么字段

    2024-06-06 10:38:03       18 阅读

最近更新

  1. kotlin typealias

    2024-06-06 10:38:03       0 阅读
  2. 如何做到高级Kotlin强化实战?(二)

    2024-06-06 10:38:03       0 阅读
  3. 力学笃行(四)Qt 线程与信号槽

    2024-06-06 10:38:03       2 阅读
  4. 【C/C++】VSCode 插件支持

    2024-06-06 10:38:03       2 阅读
  5. 华为HCIP Datacom H12-821 卷32

    2024-06-06 10:38:03       2 阅读
  6. Zookeeper底层原理

    2024-06-06 10:38:03       1 阅读

热门阅读

  1. 基于STM32的毕业设计示例

    2024-06-06 10:38:03       7 阅读
  2. 分布式和集群的区别

    2024-06-06 10:38:03       11 阅读
  3. 【Android】Android获取设备Serial Number的方法

    2024-06-06 10:38:03       9 阅读
  4. Kubernetes 之 DaemonSet 基本原理

    2024-06-06 10:38:03       10 阅读
  5. elasticSearch配置

    2024-06-06 10:38:03       10 阅读
  6. redis不同结构占用内存估算

    2024-06-06 10:38:03       10 阅读
  7. ChatGPT基本原理

    2024-06-06 10:38:03       11 阅读
  8. KNN 算法【python,机器学习,算法】

    2024-06-06 10:38:03       11 阅读
  9. su和sudu、三剑客中的sed、awk命令

    2024-06-06 10:38:03       10 阅读
  10. 如何评价GPT-4o

    2024-06-06 10:38:03       13 阅读
  11. 喷涂生产线自动化设计方案二

    2024-06-06 10:38:03       10 阅读