Android: Kotlin realizes calling camera resources to take pictures and display them

1 First understand the solution to the expiration of startActivityForResult(intent, requestCode)

Return after jumping to another interface. When the other interface is destroyed, you want to get some values ​​of the interface. The method used at this time is startActivityForResult, but as shown below, it shows that the method has expired, so use the recommended one below registerForActivityResult
insert image description here
insert image description hereUse registerForActivityResult to resolve expiration issues. Be sure to note that the position of the parameter declaration is within the Activity class, otherwise an error will be reported.

class CameraTest:AppCompatActivity() {
    
    
    //实现回调函数,用于处理返回当前界面后的数据处理
    val  launcherCallback=ActivityResultCallback<ActivityResult>{
    
     result ->
        if(result.resultCode== Activity.RESULT_OK){
    
    
           //在此处进行返回数据之后逻辑代码的处理
        }
    }
    val intentLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult(),launcherCallback)
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContentView(R.layout.camera_test)
        //点击按钮之后进行界面的跳转
        use_camera.setOnClickListener(){
    
    
            val intent= Intent(this,Another::class.java)
            intent.putExtra("key",value)
            //startActivityForResult(intent,1)//这个方法过期了,,需要使用下面这个方法
            intentLauncher.launch(intent)
        }
    }

2 Click the button to call the camera and display the result of taking pictures

1 Prepare the layout xml for displaying data

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/use_camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="点击拍照"/>

    <ImageView
        android:id="@+id/show_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>
    
</LinearLayout>

2 Process the logic of taking pictures and taking pictures

package com.njupt.kotlinlearn.notificationandmedia

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri

import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import com.njupt.kotlinlearn.R
import kotlinx.android.synthetic.main.camera_test.*
import java.io.File

class CameraTest:AppCompatActivity() {
    
    

    lateinit var imageUri:Uri
    lateinit var outPutImage:File

    //实现回调函数,当相机界面被销毁之后,图片会缓存到指定的地点,然后到指定的路径中去获取图片和显示即可
    val  launcherCallback=ActivityResultCallback<ActivityResult>{
    
     result ->
        Log.d("result","${
      
      result.data}")
        if(result.resultCode== Activity.RESULT_OK){
    
    
            val bitMap=BitmapFactory.decodeStream(contentResolver.openInputStream(imageUri))
            show_image.setImageBitmap(rotateIfRequired(bitMap))
        }
    }

    val intentLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult(),launcherCallback)

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


        use_camera.setOnClickListener(){
    
    
            //创建一个file对象,指明照片的存储路径是缓存的目录和为拍下的照片取名为output_image.jpg
            outPutImage=File(externalCacheDir,"output_image.jpg")
            if(outPutImage.exists()){
    
    
                outPutImage.delete()
            }
            outPutImage.createNewFile()
            //如果版本低于7,就用uri将file对象转化成uri对象,否则就封装成uri对象
            imageUri=if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
    
    
                //FileProvider是一种特殊的ContentProvider
                FileProvider.getUriForFile(this,"com.example.cameraalbumtest.fileprovider",outPutImage)
            }else{
    
    
                Uri.fromFile(outPutImage)
            }
            val intent= Intent("android.media.action.IMAGE_CAPTURE")
            //调用指定了图片输出的地址,当相机被调用的时候,指定了拍照之后的存储地址
            intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri)
            //startActivityForResult(intent,1)//这个方法过期了,,需要使用下面这个方法
            intentLauncher.launch(intent)
        }
    }
//处理照片拍照的旋转问题
    private fun rotateIfRequired(bitmap:Bitmap):Bitmap{
    
    
        val exif =ExifInterface(outPutImage.path)
        val orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL)
        return when(orientation){
    
    
            ExifInterface.ORIENTATION_ROTATE_90->rotateBitmap(bitmap,90)
            ExifInterface.ORIENTATION_ROTATE_180->rotateBitmap(bitmap,180)
            ExifInterface.ORIENTATION_ROTATE_270->rotateBitmap(bitmap,270)
            else->bitmap
        }
    }
    private fun rotateBitmap(bitmap:Bitmap,degree:Int):Bitmap{
    
    
        val matrix= Matrix()
        matrix.postRotate(degree.toFloat())
        val rotatedBitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.width,bitmap.height,matrix,true)
        bitmap.recycle()
        return rotatedBitmap
    }
}

3 Add the provider and data access path required by the program in xml

<provider
            android:authorities="com.example.cameraalbumtest.fileprovider"
            android:name="androidx.core.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true"
            >
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_path"/>
        </provider>

Create a new folder named xml under the res directory, and then create a new xml file named file_path under the xml folder, select paths below,

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
    name="my_images"
    path="/"/>
</paths>

Click the button to run and the result of taking pictures will appear
insert image description here

3 Deal with the problem of using the result return value of registerForActivityResult when one interface accesses multiple interfaces

Use multiple callback functions and multiple launchers to process the results


class CameraTest:AppCompatActivity() {
    
    

    lateinit var imageUri:Uri
    lateinit var outPutImage:File

    //实现回调函数,当相机界面被销毁之后,图片会缓存到指定的地点,然后到指定的路径中去获取图片和显示即可
    val  launcherCallback=ActivityResultCallback<ActivityResult>{
    
     result ->
        if(result.resultCode== Activity.RESULT_OK){
    
    
            val bitMap=BitmapFactory.decodeStream(contentResolver.openInputStream(imageUri))
            show_image.setImageBitmap(rotateIfRequired(bitMap))
        }
    }
    //在写一个回调函数用来处理其他界面返回的请求
    val  launcherCallback2=ActivityResultCallback<ActivityResult>{
    
     result ->
         if(result.resultCode== Activity.RESULT_OK){
    
    
            //要在这里面进行
            result.data!!.data?.let{
    
     uri->
                //选择显示的图片
                val bitmap=getBitMapFromUri(uri)
                show_image.setImageBitmap(bitmap)
            }
        }
    }
    private fun getBitMapFromUri(uri: Uri)=contentResolver.openFileDescriptor(uri,"r")?.use {
    
    
        BitmapFactory.decodeFileDescriptor(it.fileDescriptor) }

    val intentLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult(),launcherCallback)
    val intentLauncher2=registerForActivityResult(ActivityResultContracts.StartActivityForResult(),launcherCallback2)

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


        use_camera.setOnClickListener(){
    
    
            //创建一个file对象,指明照片的存储路径是缓存的目录和为拍下的照片取名为output_image.jpg
            outPutImage=File(externalCacheDir,"output_image.jpg")
            if(outPutImage.exists()){
    
    
                outPutImage.delete()
            }
            outPutImage.createNewFile()
            //如果版本低于7,就用uri将file对象转化成uri对象,否则就封装成uri对象
            imageUri=if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
    
    
                //FileProvider是一种特殊的ContentProvider
                FileProvider.getUriForFile(this,"com.example.cameraalbumtest.fileprovider",outPutImage)
            }else{
    
    
                Uri.fromFile(outPutImage)
            }
            val intent= Intent("android.media.action.IMAGE_CAPTURE")
            //调用指定了图片输出的地址,当相机被调用的时候,指定了拍照之后的存储地址
            intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri)
            //startActivityForResult(intent,1)//这个方法过期了,,需要使用下面这个方法
            intentLauncher.launch(intent)
        }
        select_photo_from_file.setOnClickListener(){
    
    
            val intent=Intent(Intent.ACTION_OPEN_DOCUMENT)
            intent.addCategory(Intent.CATEGORY_OPENABLE)
            //显示image目录下的所有可以打开的文件
            intent.type="image/*"
            intentLauncher2.launch(intent)
        }
    }

    private fun rotateIfRequired(bitmap:Bitmap):Bitmap{
        val exif =ExifInterface(outPutImage.path)
        val orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL)
        return when(orientation){
            ExifInterface.ORIENTATION_ROTATE_90->rotateBitmap(bitmap,90)
            ExifInterface.ORIENTATION_ROTATE_180->rotateBitmap(bitmap,180)
            ExifInterface.ORIENTATION_ROTATE_270->rotateBitmap(bitmap,270)
            else->bitmap
        }
    }
    private fun rotateBitmap(bitmap:Bitmap,degree:Int):Bitmap{
        val matrix= Matrix()
        matrix.postRotate(degree.toFloat())
        val rotatedBitmap=Bitmap.createBitmap(bitmap,0,0,bitmap.width,bitmap.height,matrix,true)
        bitmap.recycle()
        return rotatedBitmap
    }
}

Guess you like

Origin blog.csdn.net/m0_56184347/article/details/129628216