Android learning (using camera and photo album to get photos)

Some of the softwares we have used have the function for users to choose their avatars-take photos and upload them or choose from albums. So how is this achieved? First look at the renderings:

Insert picture description here
Calling the camera
First, let’s analyze how to call the camera to take a picture: the
layout file is very simple, so we don’t need to put the code, just look at the Java file:
first declare global variables public static final int TAKE_PHONE = 1;
and then process events for the camera button

button.setOnClickListener( new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //创建文件用于保存即将拍摄出的图片
        File outputImage = new File( getExternalCacheDir(),
                "outputImage.jpg");
        try{
            if(outputImage.exists())    //如果已存在就删除
                outputImage.delete();   //避免重复拍照
            outputImage.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(Build.VERSION.SDK_INT >= 24){   //SDK版本>24需要使用provider
            uri = FileProvider.getUriForFile( MainActivity.this,
                    "com.angel.hand.cameraalbumtest.fileprovider",
                    outputImage);
        }
        else uri = Uri.fromFile( outputImage );  //sdk版本低则不需要
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");   //使用Intent打开相机
        intent.putExtra( MediaStore.EXTRA_OUTPUT,uri );
        startActivityForResult( intent,TAKE_PHONE );    //为了获取拍摄到的图片需要重写返回方法
    }
} );

Then the rewrite of onActivityForResult

//我们使用startActivityForResult来获得拍摄完的照片,因此要重写此方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
    switch (requestCode){
        case TAKE_PHONE:    //开始声明的全局变量,用于区分直接拍照或是从相册选取
            if(resultCode == RESULT_OK){
                try {
                    //通过url获取图片内容并转为Bitmap格式(用于显示图片)
                    Bitmap bitmap = BitmapFactory.decodeStream( getContentResolver().openInputStream( uri ) );
                    imageView.setImageBitmap( bitmap );   //将图片显示到ImageView上
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
            break;  
       default:
            break;
    }
}

It’s not over yet, but also declare the provider mentioned earlier

<application
	...
<provider
        android:authorities="com.angel.hand.cameraalbumtest.fileprovider" //这个名字要与之前声明的相同
        android:name="android.support.v4.content.FileProvider" //这个名字时固定的
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data  //指定uri的共享路径
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" //指定路径,自己创建
            />
    </provider>

New file_paths (new xml file in res)

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="my_images"  //name的值任意
        path="" /> //为空代表整个sd卡都共享
</paths>

Let's first analyze the whole process roughly: Click the button to trigger an event-create a space in the cache in advance to save the captured pictures-get the address of this space and save it in uri format-Intent notifies the camera to start taking pictures ——Click √ to take the picture successfully——Save the captured picture in the pre-created space——Convert the content in this space into picture format——Display the picture on the imageview control.
Here you need to pay attention to: android7.0 It is considered unsafe to start using the real path uri, so FileProvider is needed to encapsulate the uri. Before 4.4 system, access to SD card requires permission, so if necessary, declare the permission to access SD card in androidmanifest.xml file

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...   
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Let’s take a look at how to select a picture from the album to
call the album.
First, it is the global variable public static final int CHOOSE_PHOTO = 2;
and then the button processing event

button1.setOnClickListener( new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        //首先检查访问权限,如果没有权限就提示用户allow一下
        if(ContextCompat.checkSelfPermission( MainActivity.this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE ) !=
                PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions( MainActivity.this,
                    new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }
        //允许后打开相册
        else openAlbum();
    }
} );

Then there is the rewritten request permission method

//请求用户访问权限
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
        case 1:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                openAlbum();
            } else {
                Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
            }
            break;
        default:
    }
}

Open the album, because it is used twice, it is packaged into one method

private void openAlbum() {
    //打开相册的方法,同样是使用的Intent
    Intent intent = new Intent( "android.intent.action.GET_CONTENT" );
    intent.setType( "image/*" );  //打开的是图片
    startActivityForResult( intent, CHOOSE_PHOTO);
}

Add a new case under the onActivityResult method

case CHOOSE_PHOTO:
    if(resultCode == RESULT_OK){
        if(Build.VERSION.SDK_INT >= 19){    //在sdk版本大于19时采用这种方法获取图片
            handleImageOnKitKat(data);
        }
        else handleImageBeforeKitKat( data );   //低版本则使用此方法(这两个都需要自己创建)
    }
    break;

Two versions of how to get uir

//4.4版本之前可以直接获取uri
private void handleImageBeforeKitKat(Intent data) {
    Uri uri = data.getData();
    String imagePath = getImagePath( uri, null );
    displayImage(imagePath);
}
//4.4之后的版本,需要对uri进行处理
@TargetApi( 19 )
private void handleImageOnKitKat(Intent data) {
    String imagepath = null;
    Uri uri = data.getData();
    if(DocumentsContract.isDocumentUri( this, uri )){
        String docId = DocumentsContract.getDocumentId( uri );
        //document类型处理方法-media文件,通过douument id处理
        if("com.android.providers.media.documents".equals( uri.getAuthority() )){
            String id = docId.split( ":" )[1];  //解析出数字格式的id
            String selection = MediaStore.Images.Media._ID + "=" + id;
            imagepath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
        }
        else if("com.android.providers.downloads.documents".equals( uri.getAuthority() )){
            Uri contentUri = ContentUris.withAppendedId( Uri.parse( "content://downloads/public_downloads" ), Long.valueOf( docId ) );
            imagepath = getImagePath(contentUri, null);
        }
    }
    //content类型处理方法,用普通方法处理
    else if("content".equalsIgnoreCase( uri.getScheme() )){
        imagepath = getImagePath(uri, null);
    }
    //file类型处理方法,直接获取图片路径
    else if("file".equalsIgnoreCase( uri.getScheme() )){
        imagepath = uri.getPath();
    }
    //将图片显示
    displayImage( imagepath );
}

The getImagePath method of directly obtaining the uri (not a system method, written by yourself)

private String getImagePath(Uri uri, String selection) {
    String path = null;
    // 通过Uri和selection来获取真实的图片路径
    Cursor cursor = getContentResolver().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;
}

Display pictures, used many times, so encapsulate them into methods

//将图片显示到imageview控件上
private void displayImage(String imagePath) {
    if(imagePath != null){
        Bitmap bitmap = BitmapFactory.decodeFile( imagePath );
        imageView.setImageBitmap( bitmap );
    }
    else Toast.makeText( this, "faild to get image", Toast.LENGTH_SHORT ).show();
}

Let's analyze the general process: Click the button to trigger the event-if you don't have access permission, apply-open the album after having access permission-get the picture uri (two methods for different versions)-convert the picture from the address to Picture format-displayed on the imageview control. Points
to note: Reading and writing the hard disk is a dangerous operation, so we need to apply for permission. In addition, since version 4.4 cannot directly access the uri (provider is used when taking pictures), two methods of obtaining uri need to be written for the two versions, the lower version is directly obtained, and the higher version needs to parse the uri.
The code is mainly learned from Guo Shen

Guess you like

Origin blog.csdn.net/qq_42893430/article/details/90477921