Android 调用相册获取图片和视频 (笔记)

2,977 阅读6分钟

前言:

这个纯属笔记 如果你是做APP 可以用方便三方库来实现更好,废话不多说我们正式开始

效果图:

6865547-6eaf5e2f9484e3b8.png

布局代码:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".TestActivity">
    <Button
        android:id="@+id/getimg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="上传图片"
        android:layout_marginTop="10dp"
        >
    </Button>

    <Button
        android:id="@+id/getvideo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="上传视频"
        android:layout_marginTop="10dp"
        >
    </Button>
    <ImageView
        android:id="@+id/test_img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </ImageView>
</LinearLayout>

布局预览

6865547-518a922874e73a38.png 我们就写了2个button 分别来触发这个上传图片和上传视频的事件

从相册中选择图片

     /**
     * 从相册中选择图片
     */
    private  void openPhoto(int openPhotoCode){
        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, openPhotoCode);
    }

从相册中选择视频

    /**
     * 从相册中选择视频
     */
    private void choiceVideo(int openVideoCode) {
        Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(i, openVideoCode);
    }

我们封装2个方法分别打开相册获取视频和图片的

//获取图片

  findViewById(R.id.getimg).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    int hasWritePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    List<String> permissions = new ArrayList<String>();
                    if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
                        permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    } else {
                        openPhoto(1);
                    }
                    if (!permissions.isEmpty()) {
                        ActivityCompat.requestPermissions((Activity) mContext, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                REQUEST_PERMISSION);
                    }
                }else {
                    openPhoto(1);
                }
            }
        });

// 获取视频

  findViewById(R.id.getvideo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    int hasWritePermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    List<String> permissions = new ArrayList<String>();
                    if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
                        permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
                    } else {
                        choiceVideo(6);
                    }
                    if (!permissions.isEmpty()) {
                        ActivityCompat.requestPermissions((Activity) mContext, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                REQUEST_PERMISSION);
                    }
                }else {
                    choiceVideo(6);
                }
            }
        });

获取图片和视频结果处理

我们在 onActivityResult 方法里面来处理 我们分别写了 getphotoResult方法和getVideoFileResult 方法来处理视频结果图片结果

   protected void onActivityResult(int requestCode, int resultCode, Intent data){
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode >=1&&requestCode<=5) {
            // 从相册返回的数据
            if (data != null) {
                getphotoResult(requestCode,resultCode,data);
            }
        }else if (requestCode>=6&&requestCode<=10 && resultCode == RESULT_OK && null != data) {
            getVideoFileResult(requestCode,resultCode,data);
        }
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
    }

图片结果处理

    //处理获取到的图片文件
    private void  getphotoResult(int requestCode, int resultCode, Intent data){
        // 得到图片的全路径
        if(requestCode==1){
            Uri uri = data.getData();
            Log.e(TAG, "onActivityResult:uri "+uri );
            testimage.setImageURI(uri);
            String imagePath = ImageUtils.getImagePath(uri, null, (Activity) mContext);
            Log.e(TAG, "onActivityResult:imagePath  "+imagePath);
            if(!TextUtils.isEmpty(imagePath)){
                File file=new File(imagePath);
            }
        }
    }

视频结果处理

   //处理获取到视频文件
    private void getVideoFileResult(int requestCode, int resultCode, Intent data){
        Uri selectedVideo = data.getData();
        String[] filePathColumn = {MediaStore.Video.Media.DATA};
        Cursor cursor = getContentResolver().query(selectedVideo,
                filePathColumn, null, null, null);
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String  videopath = cursor.getString(columnIndex);
        Log.e(TAG, "onActivityResult:VIDEOPATH   --- > "+ videopath);
        Double size= FileSizeUtil.getFileOrFilesSize(videopath,3);
        Log.e(TAG, "onActivityResult:size  --- >  "+size);
        if(size<30.0){
            File viodefile=new File(videopath);
        }else{
            Toast.makeText(mContext,"视频大小不能超过30MB请调整大小",Toast.LENGTH_SHORT).show();
        }
        cursor.close();
    }

图片 视频 URI 转换工具类

package com.example.camerademo;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
 *
 * 创建人:xuqing
 * 创建时间:2020年8月25日16:42:38
 * 类说明:图片加载类
 *
 */
public class ImageUtils {
    //加载网络图片
    public   static  void showImage(final Activity context, final String url, final ImageView
                                       imageView){
        new Thread(new Runnable() {
            @Override
            public void run() {
                final Bitmap bitmap=getImageBitmap(url);
                context.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        imageView.setImageBitmap(bitmap);
                    }
                });

            }
        }).start();
    }
    //将图片URL地址转换成Bitmap
    public static Bitmap getImageBitmap(String url) {
        URL imgUrl = null;
        Bitmap bitmap = null;
        try {
            imgUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) imgUrl
                    .openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }
    // 将uri 转换成path路径
    public static String getImagePath(Uri uri, String selection, Activity activity) {
        String path = null;
        Cursor cursor = activity.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;
    }
}

文件大小工具检查工具类

 package com.example.camerademo;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.text.DecimalFormat;


/**
 *
 * 创建人:xuqing
 * 创建时间:2021年8月27日15:30:02
 * 类说明:文件大小工具类
 *
 *
 */

public class FileSizeUtil {


    private static final String TAG=FileSizeUtil.class.getSimpleName();
    public static final int SIZETYPE_B = 1;//获取文件大小单位为B的double值
    public static final int SIZETYPE_KB = 2;//获取文件大小单位为KB的double值
    public static final int SIZETYPE_MB = 3;//获取文件大小单位为MB的double值
    public static final int SIZETYPE_GB = 4;//获取文件大小单位为GB的double值

    /**
     * 获取文件指定文件的指定单位的大小
     *
     * @param filePath 文件路径
     * @param sizeType 获取大小的类型1为B、2为KB、3为MB、4为GB
     * @return double值的大小
     */
    public static double getFileOrFilesSize(String filePath, int sizeType) {
        File file = new File(filePath);
        long blockSize = 0;
        try {
            if (file.isDirectory()) {
                blockSize = getFileSizes(file);
            } else {
                blockSize = getFileSize(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG,"获取文件大小失败!");
        }
        return FormetFileSize(blockSize, sizeType);
    }

    /**
     * 调用此方法自动计算指定文件或指定文件夹的大小
     *
     * @param filePath 文件路径
     * @return 计算好的带B、KB、MB、GB的字符串
     */
    public static String getAutoFileOrFilesSize(String filePath) {
        File file = new File(filePath);
        long blockSize = 0;
        try {
            if (file.isDirectory()) {
                blockSize = getFileSizes(file);
            } else {
                blockSize = getFileSize(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG,"获取文件大小失败!");
        }
        return FormetFileSize(blockSize);
    }

    /**
     * 获取指定文件大小
     *
     * @param file
     * @return
     * @throws Exception
     */
    private static long getFileSize(File file) throws Exception {
        long size = 0;
        if (file.exists()) {
            FileInputStream fis = null;
            fis = new FileInputStream(file);
            size = fis.available();
        } else {
            file.createNewFile();
            Log.e(TAG,"获取文件大小不存在!");
        }
        return size;
    }

    /**
     * 获取指定文件夹
     *
     * @param f
     * @return
     * @throws Exception
     */
    private static long getFileSizes(File f) throws Exception {
        long size = 0;
        File flist[] = f.listFiles();
        for (int i = 0; i < flist.length; i++) {
            if (flist[i].isDirectory()) {
                size = size + getFileSizes(flist[i]);
            } else {
                size = size + getFileSize(flist[i]);
            }
        }
        return size;
    }

    /**
     * 转换文件大小
     *
     * @param fileS
     * @return
     */
    private static String FormetFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString = "";
        String wrongSize = "0B";
        if (fileS == 0) {
            return wrongSize;
        }
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "MB";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "GB";
        }
        return fileSizeString;
    }

    /**
     * 转换文件大小,指定转换的类型
     *
     * @param fileS
     * @param sizeType
     * @return
     */
    private static double FormetFileSize(long fileS, int sizeType) {
        DecimalFormat df = new DecimalFormat("#.00");
        double fileSizeLong = 0;
        switch (sizeType) {
            case SIZETYPE_B:
                fileSizeLong = Double.valueOf(df.format((double) fileS));
                break;
            case SIZETYPE_KB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1024));
                break;
            case SIZETYPE_MB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1048576));
                break;
            case SIZETYPE_GB:
                fileSizeLong = Double.valueOf(df.format((double) fileS / 1073741824));
                break;
            default:
                break;
        }
        return fileSizeLong;
    }
}

其他说明 :

Android在4.4之后的版本(包括4.4)中,从相册中选取图片返回Uri进行了改动。所以我们无法通过该Uri来取得文件路径,从而解码图片,将其显示出来。

在4.3或以下可以直接用Intent.ACTION_GET_CONTENT打开相册;在4.4或以上,官方建议用ACTION_OPEN_DOCUMENT打开相册
  • 4.4之前的版本

在4.4之前的版本,返回的Uri如下:content://media/external/images/media/8302 我们可以通过ContentResolver的查询方法来获取路径:

Uri uri = "content://media/external/images/media/8302";
String imagePath = getImagePath(uri, null);
private String getImagePath(Uri uri, String selection) {
        String path = null;
        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;
    }

代码分析,当我们通过uri得到了相册数据库图片的表,然后通过索引MediaStore.Images.Media.DATA获取所得行的"_data"列的值。这样我们就得到了具体的文件路径,可以通过创建输入流来获取相应的Bitmap,并进行显示。

  • 4.4之后的版本,包括4.4

在4.4之后的,包括4.4的版本,返回的Uri有可能是以下的一种:

private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();

        if (DocumentsContract.isDocumentUri(this, uri)) {
            String docId = DocumentsContract.getDocumentId(uri);
            if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
                //Log.d(TAG, uri.toString());
                String id = docId.split(":")[1];
                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())) {
                //Log.d(TAG, uri.toString());
                Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            //Log.d(TAG, "content: " + uri.toString());
            imagePath = getImagePath(uri, null);
        }
    }

代码分析:

判断步骤: 1首先对Uri的authority进行判断。是document类型的Uri还是普通的media类型的Uri。 由于document类型有两种:media和download类型,所以需要进一步判断。因为这里涉及Uri的id部分不同。 2 如果是普通类型,那么和4.4之前的处理完全一样。可以直接通过Uri获取文件路径。 3 如果是media类型的document Uri,我们首先通过DocumentsContract.getDocumentId(uri);获取到"image%3A8302"。然后通过String.split方法来获取真正的id。

参考

Android 4.4从图库选择图片,获取图片路径并裁剪 Android-Uri To Path

最后总结

调用相册或者相机 获取手机内存里面视频或者图片文件 是比较常见的需求 ,因为是做手游SDK开发所以基本很少去看这些原生写法 所以就做个笔记记录下

demo地址 :

gitee.com/qiuyu123/up…