一、序言

        在安卓开发过程中,有时候我们的应用需要使用手机本地图片,这就需要本地图片访问权限以及相关的获取方法,本文将手机本地图片的获取流程和代码做了一个总结,希望能够对大家有一定帮助;

二、功能分析 

2.1 获取图片信息

        首先要获取本地图片的相关信息,如:存储路径、名称等,这里就要用到ContentResolver;

private void initImages() {
    int count = 0;
    imageList = new ArrayList();
    @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, null,  null, null);
    while (cursor.moveToNext()) {
        //获取图片的名称
        String name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
        Log.d("ImgActivity: ", "initImages: " + "imageName: " + name);

        //获取图片的路径
        byte[] data = cursor.getBlob(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        String location = new String(data, 0, data.length - 1);
        Log.d("ImgActivity: ", "initImages: " + "imageLocation: " + location);
        //根据路径获取图片
        Bitmap bm = getImgFromDesc(location);

        //获取图片的详细信息
        String desc = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DESCRIPTION));
        Log.d("ImgActivity", "initImages: " + "ImageDesc: " + desc);

        Image image = new Image(bm, name, location);
        imageList.add(image);

        count++;
        if(count > 3) break;
    }
    Log.d("ImgActivity: ", "initImage: " + "imageList.size: " + imageList.size());
}

2.2 获取图片资源

        要将图片显示出来,就要获取图片资源,这里采用BitmapFactory类对相应路径下的位图资源;

//根据路径获取图片
private Bitmap getImgFromDesc(String path) {
    Bitmap bm = null;
    File file = new File(path);
    // 动态申请权限
    String[] permissions = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA};
    final int REQUEST_CODE = 10001;

    // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // 检查该权限是否已经获取

        for (String permission : permissions) {
            //  GRANTED---授权  DINIED---拒绝
            if (ContextCompat.checkSelfPermission(getApplicationContext(), permission) == PackageManager.PERMISSION_DENIED) {
                ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE);
            }
        }
    }

    boolean permission_readStorage = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
    boolean permission_camera = (ContextCompat.checkSelfPermission(getApplicationContext(),
            Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED);
    Log.d("ImgActivity:", "getImageFromDesc: \n");
    Log.d("ImgActivity: ", "readPermission: " + permission_readStorage + "\n");
    Log.d("ImgActivity: ", "cameraPermission: " + permission_camera + "\n");

    if(file.exists()) {
        bm = BitmapFactory.decodeFile(path);
    } else {
        ToastUtil.showLong("该图片不存在!");
        Log.d("ImgActivity ", "getImgFromDesc: 该图片不存在!");
    }
    return bm;
}

三、完整代码

        整个代码包括:静态\动态权限申请、Activity注册与定义、视图的定义(包括activity_img.xml和item_listview.xml)、图片实体类的定义、ImageAdapter适配器定义;

3.1 AndroidManafest.xml

        添加手机文件读写权限,注册Activity;

<!-- 获取手机外部存储读写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 手机照片访问权限 -->
<uses-permission android:name="android.permission.CAMERA"/>
<application
    <activity
        android:name=".activity.ImgActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

3.2  activity_img.xml

        使用ListView列表显示图片,ScrollView滚动列表可滚动显示更多的图片;

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <ListView
            android:id="@+id/img_list"
            android:layout_width="match_parent"
            android:layout_height="650dp"
            android:layout_weight="1"/>

    </LinearLayout>
</ScrollView>

3.3 定义item_listview.xml

        定义ListView子项的布局,即:图片资源、图片名称、图片路径这样一个结构;

<?xml version="1.0" encoding="utf-8"?>
<!-- 显示查询到的手机本地图片 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <!-- 图片显示 -->
    <ImageView
        android:id="@+id/image_img"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="10dp"/>

    <!-- 图片名称显示 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="10dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:text="图片名称: " />

        <TextView
            android:id="@+id/image_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    <!-- 图片路径显示 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginBottom="10dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:text="图片路径: " />

        <TextView
            android:id="@+id/image_location"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

 3.3 定义图片实体类

        定义Image类,用于存储图片信息;

package com.android.androidpractice0824.bean;

import android.graphics.Bitmap;

/** 图像信息类 */
public class Image {

    private Bitmap image;
    private String name;
    private String location;

    public Image(Bitmap image, String name, String location) {
        this.image = image;
        this.name = name;
        this.location = location;
    }

    public Bitmap getImage() {
        return image;
    }

    public void setImage(Bitmap image) {
        this.image = image;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
}

3.4  定义ListView的适配器

        定义ImageAdapter类,用于适配ArrayList<Image>和视图ListView;

package com.android.androidpractice0824.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.android.androidpractice0824.R;
import com.android.androidpractice0824.bean.Image;

import java.util.List;

public class ImageAdapter extends ArrayAdapter<Image> {
    private int resourceId;

    public ImageAdapter(Context context, int textViewResourceId,
                        List<Image> objects) {
        super(context, textViewResourceId, objects);
        resourceId = textViewResourceId;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Image image = getItem(position);
        View view;
        ViewHolder viewHolder;
        if(convertView == null) {
            view = LayoutInflater.from(getContext())
                    .inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.imageImage = view.findViewById(R.id.image_img);
            viewHolder.imageName = view.findViewById(R.id.image_name);
            viewHolder.imageLocation = view.findViewById(R.id.image_location);
            view.setTag(viewHolder);  //将ViewHolder储存在View中
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();  //重新获取ViewHolder
        }
        viewHolder.imageImage.setImageBitmap(image.getImage());
        viewHolder.imageName.setText(image.getName());
        viewHolder.imageLocation.setText(image.getLocation());
        return view;
    }

    class ViewHolder {
        ImageView imageImage;
        TextView imageName, imageLocation;
    }
}

3.5 定义Activity类

        定义ImageActivity类,用于处理UI的后端逻辑,以及本地图片查询等操作方法的定义;

package com.android.androidpractice0824.activity;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import com.android.androidpractice0824.R;
import com.android.androidpractice0824.Util.ToastUtil;
import com.android.androidpractice0824.adapter.ImageAdapter;
import com.android.androidpractice0824.bean.Image;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Karson Tiger
 */
//获取本地图片并显示
//参考:https://www.jb51.net/article/81948.htm
public class ImgActivity extends Activity implements View.OnClickListener{

    private List<Image> imageList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_img);
        initImages();   //初始化图片数据
        ImageAdapter adapter = new ImageAdapter(ImgActivity.this,
                R.layout.item_listview, imageList);
        ListView listView = findViewById(R.id.img_list);
        listView.setAdapter(adapter);
        ///list的点击事件
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
            @Override
            public void onItemClick (AdapterView < ? > parent, View view,int position, long id){
                Image image = imageList.get(position);
                ToastUtil.showLong("你点击了图片" + image.getName());
            }
        });
    }
    //查询图片信息
    private void initImages() {
        /* 因为手机本地图片过多,若将其全部查询出来并显示,需要耗费过多时间,
           这里定义一个count变量用于控制显示出的图片数目 */
        int count = 0;
        imageList = new ArrayList();
        @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, null,  null, null);
        while (cursor.moveToNext()) {
            //获取图片的名称
            String name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
            Log.d("ImgActivity: ", "initImages: " + "imageName: " + name);

            //获取图片的路径
            byte[] data = cursor.getBlob(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            String location = new String(data, 0, data.length - 1);
            Log.d("ImgActivity: ", "initImages: " + "imageLocation: " + location);
            //根据路径获取图片
            Bitmap bm = getImgFromDesc(location);

            //获取图片的详细信息
            String desc = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DESCRIPTION));
            Log.d("ImgActivity", "initImages: " + "ImageDesc: " + desc);

            Image image = new Image(bm, name, location);
            imageList.add(image);

            count++;
            //显示出3张图片,可改变该数字,控制显示出的图片数目
            if(count >= 3) break;
        }
        Log.d("ImgActivity: ", "initImage: " + "imageList.size: " + imageList.size());
    }

    //根据路径获取图片
    private Bitmap getImgFromDesc(String path) {
        Bitmap bm = null;
        File file = new File(path);
        // 动态申请权限
        String[] permissions = {
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA};
        final int REQUEST_CODE = 10001;
    
        // 版本判断。当手机系统大于 23 时,才有必要去判断权限是否获取
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 检查该权限是否已经获取
    
            for (String permission : permissions) {
                //  GRANTED---授权  DINIED---拒绝
                if (ContextCompat.checkSelfPermission(getApplicationContext(), permission) == PackageManager.PERMISSION_DENIED) {
                    ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE);
                }
            }
        }
    
        boolean permission_readStorage = (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED);
        boolean permission_camera = (ContextCompat.checkSelfPermission(getApplicationContext(),
                Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED);
        Log.d("ImgActivity:", "getImageFromDesc: \n");
        Log.d("ImgActivity: ", "readPermission: " + permission_readStorage + "\n");
        Log.d("ImgActivity: ", "cameraPermission: " + permission_camera + "\n");
    
        if(file.exists()) {
            bm = BitmapFactory.decodeFile(path);
        } else {
            ToastUtil.showLong("该图片不存在!");
            Log.d("ImgActivity ", "getImgFromDesc: 该图片不存在!");
        }
        return bm;
    }

}