如何使用Kotlin从Android的手机存储中提取PDF文件和图片

400 阅读5分钟

如何使用Kotlin从Android的手机存储中提取PDF文件和图片

本教程将介绍如何从你的安卓应用中打开画廊和文件应用,并挑选图片和PDF文件。

此外,你还将了解到意图,特别是隐式意图。

前提条件

理解本教程需要你具备以下条件。

  • 安装了[Android Studio IDE]。
  • 对[Kotlin]编程语言的基本了解。
  • 对[Intents]的基本了解。

目标

  • 从图库中挑选图片并加载到ImageView
  • 拍摄照片并加载到ImageView
  • 挑选PDF文件并显示在TextView

Android中的文件选择涉及到隐式意图。隐式意图是一种将用户导航到另一个应用程序的意图。要使文件选择成功,应用程序清单中必须允许某些权限。

什么是意图

意向是一种促进应用程序组件之间通信的对象。例如,当应用程序启动活动、启动服务或发送广播时,就会使用意图。

意图的类型

意图包括两种类型。

隐式意图

隐式意图是一种促进两个不同应用程序之间通信的意图类型。例如,在本教程中,我们将用隐式意图来与画廊和文件应用程序进行通信。隐式意图只需要声明要执行的一般操作。

显式意图

显式意图是一种允许应用程序组件之间通信的意图类型。例如,当你想把一个活动导航到下一个活动时,你会触发一个显式意图。理论上说得够多了,让我们来深入了解一下实现。

添加权限

权限总是被添加到AndroidManifest.xml 。在清单中添加以下权限。

 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

设计布局

布局将只包括用于显示所选PDF文件的TextView ,以及用于显示所选图片库或相机拍摄的图片的ImageView 。记得使用ConstraintLayout ,来进行设计。

简单的布局可以通过包括下面的XML代码来实现。

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageTextView"
        tools:srcCompat="@tools:sample/avatars" />

    <TextView
        android:id="@+id/imageTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="48dp"
        android:text="Click To Select Image from Storage"
        android:textColor="#03A9F4"
        android:textSize="22sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/selectedPdf"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="248dp"
        android:layout_marginEnd="16dp"
        android:padding="20dp"
        android:text="Click To Pick PDF From Storage"
        android:textColor="#0798DA"
        android:textSize="22sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

挑选图片

要打开手机的图库,你需要一个意图来处理这个动作。你将点击TextView ,它将弹出一个警报对话框,有拍摄照片或从图库中选择图片的选项。你还将在本教程中学习如何触发警报对话框。

在你的代码中添加以下函数,在从图库中选择图片或拍照时显示警报对话框。

    // Function for displaying an AlertDialogue for choosing an image
    private fun selectImage() {
        val choice = arrayOf<CharSequence>("Take Photo", "Choose from Gallery", "Cancel")
        val myAlertDialog: AlertDialog.Builder = AlertDialog.Builder(this)
        myAlertDialog.setTitle("Select Image")
        myAlertDialog.setItems(choice, DialogInterface.OnClickListener { dialog, item ->
            when {
                // Select "Choose from Gallery" to pick image from gallery
                choice[item] == "Choose from Gallery" -> {
                    val pickFromGallery = Intent(Intent.ACTION_GET_CONTENT, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
                    pickFromGallery.type = "/image"
                    startActivityForResult(pickFromGallery, 1)
                }
                // Select "Take Photo" to take a photo
                choice[item] == "Take Photo" -> {
                    val cameraPicture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                    startActivityForResult(cameraPicture, 0)
                }
                // Select "Cancel" to cancel the task
                choice[item] == "Cancel" -> {
                    myAlertDialog.dismiss()
                }
            }
        })
        myAlertDialog.show()
    }

下面是警报对话框的截图。

Alert Dialog

注意:当你只想显示图库中的图片时,你包括意图是图片,但如果你想显示视频,不要指定类型。你可以通过在你的意图中包括下面的代码来指定该类型。

pickFromGallery.type = "/image"

从图库中选择图片和通过相机拍照的区别在于意图中传递的动作类型。对于图库,可以考虑使用Intent.ACTION_GET_CONTENT ,而对于相机,你可以使用MediaStore.ACTION_IMAGE_CAPTURE

挑选PDF文件

你将学习如何从你的文件中挑选一个PDF并在TextView 。当开发一个需要用户选择一个PDF文件并上传或与其他用户分享的应用程序时,挑选PDF文件就很方便了。在你的代码中包括下面的方法,从文件中挑选一个PDF。

    // Intent for navigating to the files
    private fun selectPdf() {
        val pdfIntent = Intent(Intent.ACTION_GET_CONTENT)
        pdfIntent.type = "application/pdf"
        pdfIntent.addCategory(Intent.CATEGORY_OPENABLE)
        startActivityForResult(pdfIntent, 12)
    }

实现意图后,你需要覆盖onActivityResult 方法,如下所示。

// Override this method to allow you select an an image or a PDF
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        // For loading Image
        if (resultCode != RESULT_CANCELED) {
            when (requestCode) {
                0 -> if (resultCode == RESULT_OK && data != null) {
                    val imageSelected = data.extras!!["data"] as Bitmap?
                    imageView.setImageBitmap(imageSelected)
                }
                1 -> if (resultCode == RESULT_OK && data != null) {
                    val imageSelected = data.data
                    val pathColumn = arrayOf(MediaStore.Images.Media.DATA)
                    if (imageSelected != null) {
                        val myCursor = contentResolver.query(
                            imageSelected,
                            pathColumn, null, null, null
                        )
                        // Setting the image to the ImageView
                        if (myCursor != null) {
                            myCursor.moveToFirst()
                            val columnIndex = myCursor.getColumnIndex(pathColumn[0])
                            val picturePath = myCursor.getString(columnIndex)
                            imageView.setImageBitmap(BitmapFactory.decodeFile(picturePath))
                            myCursor.close()
                        }
                    }
                }
            }
        }

        // For loading PDF
        when (requestCode) {
            12 -> if (resultCode == RESULT_OK) {

                pdfUri = data?.data!!
                val uri: Uri = data?.data!!
                val uriString: String = uri.toString()
                var pdfName: String? = null
                if (uriString.startsWith("content://")) {
                    var myCursor: Cursor? = null
                    try {
                    // Setting the PDF to the TextView
                        myCursor = applicationContext!!.contentResolver.query(uri, null, null, null, null)
                        if (myCursor != null && myCursor.moveToFirst()) {
                            pdfName = myCursor.getString(myCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                            pdfTextView.text = pdfName
                        }
                    } finally {
                        myCursor?.close()
                    }
                }
            }
        }
    }

完整的代码实现如下。

class MainActivity : AppCompatActivity() {

    // Initializing the layout views
    private lateinit var pickImageTV: TextView
    private lateinit var imageView: ImageView
    private lateinit var pdfTextView: TextView

    private lateinit var pdfUri: Uri

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        pickImageTV = findViewById(R.id.imageTextView)
        imageView = findViewById(R.id.imageView)
        pdfTextView = findViewById(R.id.selectedPdf)

        // Setting click listener to the image TextView
        pickImageTV.setOnClickListener {
            selectImage()
        }

        // Setting click listener to the ImageView
        imageView.setOnClickListener {
            selectPdf()
        }

       // Setting click listener to the PDF TextView
        pdfTextView.setOnClickListener {
            selectPdf()
        }
    }

    private fun selectImage() {
    // Creating AlertDialog
        val choice = arrayOf<CharSequence>("Take Photo", "Choose from Gallery", "Cancel")
        val myAlertDialog: AlertDialog.Builder = AlertDialog.Builder(this)
        myAlertDialog.setTitle("Select Image")
        myAlertDialog.setItems(choice, DialogInterface.OnClickListener { dialog, item ->
            when {
                choice[item] == "Choose from Gallery" -> {
                    val pickFromGallery = Intent(Intent.ACTION_GET_CONTENT, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
                    pickFromGallery.type = "/image"
                    startActivityForResult(pickFromGallery, 1)
                }
                choice[item] == "Take Photo" -> {
                    val cameraPicture = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
                    startActivityForResult(cameraPicture, 0)
                }
                choice[item] == "Cancel" -> {
                    myAlertDialog.dismiss()
                }
            }
        })
        myAlertDialog.show()
    }
    // Intent for openning files
    private fun selectPdf() {
        val pdfIntent = Intent(Intent.ACTION_GET_CONTENT)
        pdfIntent.type = "application/pdf"
        pdfIntent.addCategory(Intent.CATEGORY_OPENABLE)
        startActivityForResult(pdfIntent, 12)
    }

    @SuppressLint("Range")
   override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        // For loading Image
        if (resultCode != RESULT_CANCELED) {
            when (requestCode) {
                0 -> if (resultCode == RESULT_OK && data != null) {
                    val imageSelected = data.extras!!["data"] as Bitmap?
                    imageView.setImageBitmap(imageSelected)
                }
                1 -> if (resultCode == RESULT_OK && data != null) {
                    val imageSelected = data.data
                    val pathColumn = arrayOf(MediaStore.Images.Media.DATA)
                    if (imageSelected != null) {
                        val myCursor = contentResolver.query(
                            imageSelected,
                            pathColumn, null, null, null
                        )
                        if (myCursor != null) {
                            myCursor.moveToFirst()
                            val columnIndex = myCursor.getColumnIndex(pathColumn[0])
                            val picturePath = myCursor.getString(columnIndex)
                            imageView.setImageBitmap(BitmapFactory.decodeFile(picturePath))
                            myCursor.close()
                        }
                    }
                }
            }
        }

        // For loading PDF
        when (requestCode) {
            12 -> if (resultCode == RESULT_OK) {

                pdfUri = data?.data!!
                val uri: Uri = data?.data!!
                val uriString: String = uri.toString()
                var pdfName: String? = null
                if (uriString.startsWith("content://")) {
                    var myCursor: Cursor? = null
                    try {
                        myCursor = applicationContext!!.contentResolver.query(uri, null, null, null, null)
                        if (myCursor != null && myCursor.moveToFirst()) {
                            pdfName = myCursor.getString(myCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                            pdfTextView.text = pdfName
                        }
                    } finally {
                        myCursor?.close()
                    }
                }
            }
        }
    }

Screenshot

结论

本教程只是为了指导你完成初步的步骤。首先,你需要尝试所提供的代码来练习和掌握这个概念。意图在Android开发中具有各种用途,应该好好理解。