Encoding Implementation of Picture Selection in android Album

Posted by kee2ka4 on Fri, 31 May 2019 22:38:19 +0200

It's convenient for android cameras to take pictures directly, but more often, we need to choose one of the pictures we already have on our mobile phones to use. Practice how to choose pictures from albums this time.
First, add a Button to the activity_main.xml file to trigger the ability to select pictures from the album.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.cofox.mycameraalbum.MainActivity">

    <Button
        android:id="@+id/button_take_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Tack Photo"/>
    <Button
        android:id="@+id/button_choose_from_album"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="Choose From Album"/>
    <ImageView
        android:id="@+id/photo_pictrue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"/>

</LinearLayout>

The android:id="@+id/button_choose_from_album" button in this code is our protagonist.
Then in MainActivity.java, add the logic of selecting pictures from the album.
Declare Button button

Button btnChooseFromAlbum = (Button)findViewById(R.id.button_choose_from_album);//Album Selection Picture Button

Click events for add buttons

//Open the album and select the picture
        btnChooseFromAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                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();
                }
            }
        });

In this code, we first judge the case of PackageManager.PERMISSION_GRANTED permission. If there is no permission, we need to add it. In some cases, open Album (); open the album.
ActivityCompat. request Permissions executes the operation of obtaining permission, and then the user chooses whether to grant permission. According to the user's choice, the system decides whether to continue the function of openAlbum(). This requires onRequest Permissions Result. The logic of the code is to execute openAlbum() if the permission is granted, and to return a prompt that the user does not have the permission if the permission is not granted. ("You denied the permision.")

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    openAlbum();
                }else{
                    Toast.makeText(this, "You denied the permision.", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }

openAlbum() is to open an album. Is the code logic clear? But it's not over yet. Because some logic is needed to open it. Look at the code for openAlbum().

private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOOSE_PHOTO);//Open Album
    }

Here Intent is prepared for the album, and then calls startActivityForResult() to open the album. The CHOOSE_PHOTO that appears at this time is a conditional parameter for judging which branch to go in onActivityResult. We should add a global variable declaration in MainActivity.java

public static final int CHOOSE_PHOTO = 2;

Add the CHHOOSE_PHOTO branch of switch case to onActivityResult. Within a fraction, different code logic is executed according to different system versions. Because android 4.4 is a watershed of file access security, systems below 4.4 use direct file addresses, and systems above 4.4 no longer return real picture addresses. So the way code is handled is different. 4.4 and above systems need to parse the image address returned from the album. There are two methods to deal with handleImageOnKitKat(data) and handeleImageBeforeKitKat(data) respectively.

case CHOOSE_PHOTO:
                if(resultCode == RESULT_OK){
                    //Judging the Version Number of Mobile Phone System
                    if(Build.VERSION.SDK_INT >= 19){
                        //4.4 and above systems use this method to process pictures
                        handleImageOnKitKat(data);
                    }else{
                        //4.4 The following systems use this method to process pictures
                        handeleImageBeforeKitKat(data);
                    }
                }
                break;

The address is parsed in handleImage OnKit Kat (data), and different methods are used according to three different ways of providing Uri.
Uri of document type
uri of content type
Uri of file type

    @TargetApi(19)
    private void handleImageOnKitKat(Intent data) {
//        Toast.makeText(this, "to the handleImageOnKitKat(Intent data) method". Toast.LENGTH_LONG).show();
        String imagePath = null;
        Uri uri = data.getData();
        if(DocumentsContract.isDocumentUri(this, uri)){
            //If it's Uri of document type, it's handled by document id
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id = docId.split(":")[1];//Resolve the id of the digital format
                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);
            }
        }else if ("content".equalsIgnoreCase(uri.getScheme())){
            //If it's a uri of content type, it's handled in a normal way
            imagePath = getImagePath(uri, null);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
            //If it's Uri of file type, just get the image path directly.
            imagePath = uri.getPath();
        }
        displayImage(imagePath);//Display the selected picture
    }

Note the @TargetApi(19), because our project has a minimum compatibility system set to 15, and the DocumentsContract.isDocumentUri and DocumentsContract.getDocumentId in the code have system compatibility to deal with.
When we have obtained the path of the picture through various ways, we will naturally display the picture. So the last line of code calls the displayImage method to display the picture.
It's much simpler for handele Image BeforeKit Kat. Get the address display directly.

    private void handeleImageBeforeKitKat(Intent data){
        Uri uri = data.getData();
        String imagePath = getImagePath(uri, null);
        displayImage(imagePath);
    }

The method of obtaining the real path of the picture and displaying the picture is as follows:

    private String getImagePath(Uri uri, String selection) {
        String path = null;
        //Get the real image path through Uri and 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;
    }

    private void displayImage(String imagePath) {
        if(imagePath != null){
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            picture.setImageBitmap(bitmap);
        }else{
            Toast.makeText(this,"failed to get image", Toast.LENGTH_LONG).show();
        }
    }

MainActivity.java complete code:

package com.cofox.mycameraalbum;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    public static final int TAKE_PHOTO = 1;
    public static final int CHOOSE_PHOTO = 2;
    private ImageView picture;
    private Uri imageUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btnTakePhoto = (Button) findViewById(R.id.button_take_photo);    //Photo button
        Button btnChooseFromAlbum = (Button)findViewById(R.id.button_choose_from_album);//Album Selection Picture Button
        picture = (ImageView) findViewById(R.id.photo_pictrue);                 //Picture control, used to display photos.

        //Turn on the camera and take pictures
        btnTakePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Create File objects to store photographed images
                File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
                try {
                    if (outputImage.exists()) {
                        outputImage.delete();
                    }
                    outputImage.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //For systems under version 7.0 of android, the real file path is obtained directly from Uri.fromFile; for systems above version 7.0, the Uri encapsulated by fileprovider is provided again.
                if (Build.VERSION.SDK_INT >= 24) {
                    imageUri = FileProvider.getUriForFile(MainActivity.this, "com.cofox.mycameraalbum.fileprovider", outputImage);
                } else {
                    imageUri = Uri.fromFile(outputImage);
                }
                //Start Camera Program
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, TAKE_PHOTO);     //Start the Intent activity and the result will be returned to the onActivityResult() method after taking the photo.
            }
        });

        //Open the album and select the picture
        btnChooseFromAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                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();
                }
            }
        });
    }

    private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOOSE_PHOTO);//Open Album
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    openAlbum();
                }else{
                    Toast.makeText(this, "You denied the permision.", Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case TAKE_PHOTO:
                if(resultCode == RESULT_OK){
                    try {
                        //Show pictures taken
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        picture.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }

                }
                break;
            case CHOOSE_PHOTO:
                if(resultCode == RESULT_OK){
                    //Judging the Version Number of Mobile Phone System
                    if(Build.VERSION.SDK_INT >= 19){
                        //4.4 and above systems use this method to process pictures
                        handleImageOnKitKat(data);
                    }else{
                        //4.4 The following systems use this method to process pictures
                        handeleImageBeforeKitKat(data);
                    }
                }
                break;
            default:
                break;
        }
    }

    @TargetApi(19)
    private void handleImageOnKitKat(Intent data) {
//        Toast.makeText(this, "to the handleImageOnKitKat(Intent data) method". Toast.LENGTH_LONG).show();
        String imagePath = null;
        Uri uri = data.getData();
        if(DocumentsContract.isDocumentUri(this, uri)){
            //If it's Uri of document type, it's handled by document id
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id = docId.split(":")[1];//Resolve the id of the digital format
                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);
            }
        }else if ("content".equalsIgnoreCase(uri.getScheme())){
            //If it's a uri of content type, it's handled in a normal way
            imagePath = getImagePath(uri, null);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
            //If it's Uri of file type, just get the image path directly.
            imagePath = uri.getPath();
        }
        displayImage(imagePath);//Display the selected picture
    }

    private void handeleImageBeforeKitKat(Intent data){
        Uri uri = data.getData();
        String imagePath = getImagePath(uri, null);
        displayImage(imagePath);
    }

    private String getImagePath(Uri uri, String selection) {
        String path = null;
        //Get the real image path through Uri and 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;
    }

    private void displayImage(String imagePath) {
        if(imagePath != null){
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            picture.setImageBitmap(bitmap);
        }else{
            Toast.makeText(this,"failed to get image", Toast.LENGTH_LONG).show();
        }
    }
}

Take a look at Android Manifest. XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.cofox.mycameraalbum">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <provider
            android:authorities="com.cofox.mycameraalbum.fileprovider"
            android:name="android.support.v4.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>

</manifest>

The running effect pictures are as follows:



Main interface

Choose where to open the file

Select pictures

Confirm picture

Normal display of pictures

Topics: Android Java FileProvider xml