美文网首页Android收藏集AndroidAndroid控件
Android调用相册、相机(兼容6.0、7.0、8.0)

Android调用相册、相机(兼容6.0、7.0、8.0)

作者: 吾乃韩小呆 | 来源:发表于2018-08-19 01:38 被阅读107次

    又好久没有写博客了,好习惯不能断,该写点就得写点,今天带来的笔记是关于Android 项目调用系统相机 与调用系统相册的之后拿到照片的基本操作,我感觉好多人还是不太熟悉的哈。项目兼容 Android 5.0设备、Android 6.0设备、Android 7.0、Android 8.0等设备,下面请开始欣赏我的表演,先上动画,给大家看一下效果哈。

    Android 5.0设备效果:


    小米 2s 测试效果

    Android 6.0设备效果:


    小米4测试效果

    Android 8.0 设备效果:


    小米8se 测试

    看了三个小动画,感觉就是相机效果越来越清楚了(说人话),好的回归正题

    一、界面上定义了三个按钮,一个imageview代码还是扔上来吧,

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/btn_get_pic_form_photo_album"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_margin="10dp"
            android:text="调用相册" />
    
        <Button
            android:id="@+id/btn_get_Permission"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_margin="10dp"
            android:text="动态权限申请" />
    
        <Button
            android:id="@+id/btn_get_pic_from_camera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_margin="10dp"
            android:text="调用相机" />
    
        <ImageView
            android:id="@+id/iv_test"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_centerInParent="true"
            android:contentDescription="@string/app_name"
            android:scaleType="fitXY"
            tools:src="@mipmap/ic_launcher" />
    
    </RelativeLayout>
    

    这里没什么好说的,

    二、引入框架

    我这个人很懒,引入了 glide
    图片加载框架和easypermissions动态权限申请框架,两个十分好用的框。

     //glide 图片加载
        implementation 'com.github.bumptech.glide:glide:4.8.0'
        annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
        //动态权限申请库
        implementation 'pub.devrel:easypermissions:1.3.0'
    

    三、简单说一下easypermissions框架使用

    众所周知,Android 6.0 开始 google 爸爸引入了动态权限机制,所谓来保护用户隐私(其实就是对开发者坑爹,个人见解)。但是我们必须处理啊,毕竟是google 爸爸。

    以下仅仅以本项目所申请权限为例进行讲解。

    1、AndroidManifest.xml 内操作

     <!--读写内存块权限-->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <!--调用相机权限-->
        <uses-permission android:name="android.permission.CAMERA" />
    

    2、初始化集合装载权限

     private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    

    3、检查权限、申请权限

     //获取权限
        private void getPermission() {
            if (EasyPermissions.hasPermissions(this, permissions)) {
                //已经打开权限
                Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show();
            } else {
                //没有打开相关权限、申请权限
                EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions);
            }
    
        }
    

    4、实现接口

    在所运用权限申请的界面实现EasyPermissions.PermissionCallbacks接口

    5、处理回调

    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            //框架要求必须这么写
            EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
        }
    
        
        //成功打开权限
        @Override
        public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
            
            Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show();
        }
        //用户未同意权限
        @Override
        public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
            Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show();
        }
    
    

    四、调用相机 适配>=6.0以上设备

    1、AndroidManifest.xml 内操作

       <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.example.hxd.pictest.fileprovider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths" />
            </provider>
    

    其中,android:authorities="com.example.hxd.pictest.fileprovider"的值其实是:项目包名.fileprovider

    2、创建file_paths.xml文件

    在 项目 res 下面创建 xml 文件夹,xml文件夹下创建 file_paths.xml 文件,文件内写如下:内容

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

    文件创建,如下图:


    创建文件顺序

    3、点击按钮拍照

      private File cameraSavePath;//拍照照片路径
      private Uri uri;//照片uri
    
       //激活相机操作
        private void goCamera() {
        cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");
    
    
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //第二个参数为 包名.fileprovider
                uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            } else {
                uri = Uri.fromFile(cameraSavePath);
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            MainActivity.this.startActivityForResult(intent, 1);
        }
    

    4、获取照片并且展示

    Android 6.0以上设备的照片路径 就是你声明的uri。

       if (requestCode == 1 && resultCode == RESULT_OK) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    photoPath = String.valueOf(cameraSavePath);
                } else {
                    photoPath = uri.getEncodedPath();
                }
                Log.d("拍照返回图片路径:", photoPath);
                Glide.with(MainActivity.this).load(photoPath).into(ivTest);
            }
    

    总结,截止到这里,你拍摄的照片就可以拿到并且进行显示了,这里使用到了强大的Glide 图片加载器省去了很多自己要写的代码。很方便。

    五、相册内选照片

    1、调去系统相册

      //激活相册操作
        private void goPhotoAlbum() {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_PICK);
            intent.setType("image/*");
            startActivityForResult(intent, 2);
        }
    

    2、获取相册返回的uri

    这里封装了一个工具类,根据不同版本系统返回不同类型的uri ,这个工具类保留简单好用

    
    import android.annotation.SuppressLint;
    import android.content.ContentUris;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Build;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    /**
     * Content:从相册内获取照片转化工具类
     * Actor:韩小呆 ヾ(✿゚▽゚)ノ
     * Time:  2018/08/18 18:54
     * Update:
     * Time:
     */
    public class getPhotoFromPhotoAlbum {
        /**
         * 根据Uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        public static String getRealPathFromUri(Context context, Uri uri) {
            int sdkVersion = Build.VERSION.SDK_INT;
            if (sdkVersion >= 19) { 
                return getRealPathFromUriAboveApi19(context, uri);
            } else {
                return getRealPathFromUriBelowAPI19(context, uri);
            }
        }
    
        /**
         * 适配api19以下(不包括api19),根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
            return getDataColumn(context, uri, null, null);
        }
    
        /**
         * 适配api19及以上,根据uri获取图片的绝对路径
         *
         * @param context 上下文对象
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        @SuppressLint("NewApi")
        private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
            String filePath = null;
            if (DocumentsContract.isDocumentUri(context, uri)) {
                // 如果是document类型的 uri, 则通过document id来进行处理
                String documentId = DocumentsContract.getDocumentId(uri);
                if (isMediaDocument(uri)) {
                    // 使用':'分割
                    String id = documentId.split(":")[1];
    
                    String selection = MediaStore.Images.Media._ID + "=?";
                    String[] selectionArgs = {id};
                    filePath = getDataColumn(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs);
                } else if (isDownloadsDocument(uri)) { 
                    Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(documentId));
                    filePath = getDataColumn(context, contentUri, null, null);
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) {
                // 如果是 content 类型的 Uri
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equals(uri.getScheme())) {
                // 如果是 file 类型的 Uri,直接获取图片对应的路径
                filePath = uri.getPath();
            }
            return filePath;
        }
    
        /**
         * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
         *
         */
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
            String path = null;
    
            String[] projection = new String[]{MediaStore.Images.Media.DATA};
            Cursor cursor = null;
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                    path = cursor.getString(columnIndex);
                }
            } catch (Exception e) {
                if (cursor != null) {
                    cursor.close();
                }
            }
            return path;
        }
    
        /**
         * @param uri the Uri to check
         * @return Whether the Uri authority is MediaProvider
         */
        private static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri the Uri to check
         * @return Whether the Uri authority is DownloadsProvider
         */
        private static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    }
    
    

    3、拿到图片,展示图片

    if (requestCode == 2 && resultCode == RESULT_OK) {
                photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
                Glide.with(MainActivity.this).load(photoPath).into(ivTest);
            }
    

    六、贴出 Activity 内完整代码

    public class MainActivity extends AppCompatActivity implements View.OnClickListener, EasyPermissions.PermissionCallbacks {
    
        private ImageView ivTest;
    
        private File cameraSavePath;//拍照照片路径
        private Uri uri;
        private String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button btnGetPicFromCamera = findViewById(R.id.btn_get_pic_from_camera);
            Button btnGetPicFromPhotoAlbum = findViewById(R.id.btn_get_pic_form_photo_album);
            Button btnGetPermission = findViewById(R.id.btn_get_Permission);
            ivTest = findViewById(R.id.iv_test);
    
            btnGetPicFromCamera.setOnClickListener(this);
            btnGetPicFromPhotoAlbum.setOnClickListener(this);
            btnGetPermission.setOnClickListener(this);
    
            cameraSavePath = new File(Environment.getExternalStorageDirectory().getPath() + "/" + System.currentTimeMillis() + ".jpg");
    
        }
    
        @Override
        public void onClick(View v) {
            int id = v.getId();
            switch (id) {
                case R.id.btn_get_pic_from_camera:
                    goCamera();
                    break;
                case R.id.btn_get_pic_form_photo_album:
                    goPhotoAlbum();
                    break;
                case R.id.btn_get_Permission:
                    getPermission();
                    break;
            }
        }
    
        //获取权限
        private void getPermission() {
            if (EasyPermissions.hasPermissions(this, permissions)) {
                //已经打开权限
                Toast.makeText(this, "已经申请相关权限", Toast.LENGTH_SHORT).show();
            } else {
                //没有打开相关权限、申请权限
                EasyPermissions.requestPermissions(this, "需要获取您的相册、照相使用权限", 1, permissions);
            }
    
        }
    
    
        //激活相册操作
        private void goPhotoAlbum() {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_PICK);
            intent.setType("image/*");
            startActivityForResult(intent, 2);
        }
    
        //激活相机操作
        private void goCamera() {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                uri = FileProvider.getUriForFile(MainActivity.this, "com.example.hxd.pictest.fileprovider", cameraSavePath);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            } else {
                uri = Uri.fromFile(cameraSavePath);
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            MainActivity.this.startActivityForResult(intent, 1);
        }
    
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            //框架要求必须这么写
            EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
        }
    
    
        //成功打开权限
        @Override
        public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
    
            Toast.makeText(this, "相关权限获取成功", Toast.LENGTH_SHORT).show();
        }
        //用户未同意权限
        @Override
        public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
            Toast.makeText(this, "请同意相关权限,否则功能无法使用", Toast.LENGTH_SHORT).show();
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            String photoPath;
            if (requestCode == 1 && resultCode == RESULT_OK) {
    
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    photoPath = String.valueOf(cameraSavePath);
                } else {
                    photoPath = uri.getEncodedPath();
                }
                Log.d("拍照返回图片路径:", photoPath);
                Glide.with(MainActivity.this).load(photoPath).into(ivTest);
            } else if (requestCode == 2 && resultCode == RESULT_OK) {
                photoPath = getPhotoFromPhotoAlbum.getRealPathFromUri(this, data.getData());
                Glide.with(MainActivity.this).load(photoPath).into(ivTest);
            }
    
            super.onActivityResult(requestCode, resultCode, data);
        }
    
    
    }
    

    总结:没做事情之前,永远不要把事情想的特别难;每天进步一点点,不要嫌少,日久天长,也是满满的收获。

    demo源码:PicTest

    相关文章

      网友评论

      本文标题:Android调用相册、相机(兼容6.0、7.0、8.0)

      本文链接:https://www.haomeiwen.com/subject/mxnxiftx.html