Android 拍照及从相册选择图片传详解

先上图

新知识点速览

  1. URI(统一资源标识符)是标识逻辑或物理资源的字符序列,与URL类似,也是一串字符。通过使用位置,名称或两者来标识Internet上的资源;它允许统一识别资源。
    有两种类型的URI,统一资源标识符(URI)和统一资源名称(URN)

    任何URI的通用格式都是:

    scheme:[// [user:password @] host [:port]] [/] path [?查询] [#片段]

  2. 关联缓存目录就是SD卡中专门用于存放当前应用缓存的数据位置,使用关联缓存目录可以跳过Android6以上的权限问题

  3. 从Android6开始读写SD卡被列为危险权限,如果将图片放到SD卡或其他任何目录都要进行运行时权限处理,从Android7开始直接使用本地真实的路径的Uri被认为是不安全的,会抛出一个FileUriExposedException异常
    从Android4.4开始选取相册中的图片不再返回真实的Uri,而是一个封装过的uri

  4. FileProvider则是一种特殊的内容提供器,它使用了和内容提供器类似的机制来对数据进行保护,可以选择性的将封装过的Uri共享给外部,从而提高了应用的安全性

  5. 打开相机的方法

Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");

实例

AndroidManifest.xml配置

Android10版本不加android:requestLegacyExternalStorage="true"会报错

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.camerastuday"><uses-permission android:name="android.permission.CAMERA"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:requestLegacyExternalStorage="true"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.CameraStuday"><provider<!-- 必须与后面的Provider中的authorities相同 -->android:authorities="com.example.camerastuday.fileProvider"<!-- name属性是固定的 -->android:name="androidx.core.content.FileProvider"android:exported="false"android:grantUriPermissions="true"><!-- 通过meta标签来指定Uri的共享路径 --><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_path"/></provider><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

file_path配置资源

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-pathname="mt-image"path="."/>
</paths>
<!-- .表示将整个SD卡目录进行共享 -->

java核心代码

package com.example.camerastuday;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;import android.Manifest;
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.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;import com.google.android.material.snackbar.Snackbar;import java.io.File;
import java.io.FileNotFoundException;
import java.net.URI;public class MainActivity extends AppCompatActivity {private static final String TAG = "TAG";private Button btnGetPhotoWithCamera;private Button btnGetPhotoInRes;private ImageView IVShowImage;private Uri imageUri;private final int REQUESTCONDE_FORPERMISSONS = 2;private String[] permissions = {Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.MANAGE_EXTERNAL_STORAGE};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnGetPhotoWithCamera = findViewById(R.id.btn_GetPhotoWithCamera);btnGetPhotoInRes = findViewById(R.id.btn_GetPhotoInRes);IVShowImage = findViewById(R.id.IV_showImage);initView();}//动态申请权限public void RequestPermissions(){for (int i = 0; i < permissions.length; i++) {if (ContextCompat.checkSelfPermission(MainActivity.this,permissions[i]) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(MainActivity.this,permissions,REQUESTCONDE_FORPERMISSONS);}}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode){case REQUESTCONDE_FORPERMISSONS:for (int i = 0; i < grantResults.length; i++) {if (grantResults.length>0 && grantResults[i]==PackageManager.PERMISSION_GRANTED){Log.d(TAG, "onRequestPermissionsResult: "+"成功申请到" + permissions[i]);}else{Toast.makeText(this, permissions[i]+"未成功申请成功", Toast.LENGTH_SHORT).show();}}break;}}public void initView() {RequestPermissions();//拍照btnGetPhotoWithCamera.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//通过getExternalCacheDir()得到关联缓存目录File OutImage = new File(getExternalCacheDir(), "outPut_image.jpg");try {if (OutImage.exists()) {//如果文件存在,就删掉OutImage.delete();}//创建一个新文件OutImage.createNewFile();} catch (Exception e) {}if (Build.VERSION.SDK_INT >= 24) {//getUriForFile() 将一个File对象转化成一个封装过的Uri对象,注意第二个参数com.example.camerastuday时包名imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.camerastuday.fileProvider", OutImage);} else {imageUri = Uri.fromFile(OutImage);}//打开相机部分Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");//指定输出图片的地址intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);startActivityForResult(intent, 1);}});//从相册选择btnGetPhotoInRes.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//打开相册openColumn();}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode){case 1:if (resultCode==RESULT_OK){try {//将图片转为BitmapBitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));//设置图片IVShowImage.setImageBitmap(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;case 2:if (resultCode==RESULT_OK){if (Build.VERSION.SDK_INT>=19){if (data!=null){//4.4及以上采用这个方法handleImageONKitKat(data);}else{//4.4系统一下采用这个方法handleImageBeforeKitKat(data);}}}break;}}@RequiresApi(api = Build.VERSION_CODES.KITKAT)private void handleImageONKitKat(Intent data){String imagePath = null;Uri uri = data.getData();Log.d(TAG, "uri=: "+uri);  //     content://com.android.providers.media.documents/document/image%3A37Log.d(TAG, "getUri`s Authority: "+uri.getAuthority());  //输出是这样的:  com.android.providers.media.documentsif (DocumentsContract.isDocumentUri(this,uri)){//如果document的类型是uri,则通过document id处理String docId = DocumentsContract.getDocumentId(uri);Log.d(TAG, "docId=: "+docId); //输出是这样的:  image:37if ("com.android.providers.media.documents".equals(uri.getAuthority())){//解析出数字格式的IDString id = docId.split(":")[1];Log.d(TAG, "id=: "+id); //37String selection = MediaStore.Images.Media._ID + "=" + id;Log.d(TAG, "selection=: "+selection);  //_id=37imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection);Log.d(TAG, "imagePath=: "+imagePath);  ///storage/emulated/0/Download/R65398d6ad86129f9628c0ad80da4040c.jpeg}else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){Uri contentUIri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));Log.d(TAG, "contentUIri: "+contentUIri);imagePath = getImagePath(contentUIri,null);  ///storage/emulated/0/Download/R65398d6ad86129f9628c0ad80da4040c.jpeg}}else if ("content".equalsIgnoreCase(uri.getScheme())){imagePath = getImagePath(uri,null);}else if ("file".equalsIgnoreCase(uri.getScheme())){imagePath = uri.getPath();}disPlayImage(imagePath);}public void handleImageBeforeKitKat(Intent data){Uri uri = data.getData();String imagePath = getImagePath(uri,null);disPlayImage(imagePath);}//打开相册public void openColumn(){Intent intent = new Intent("android.intent.action.GET_CONTENT");//选择文件的格式,除此之外还有  intent.setType(“audio/*”); //选择音频 //intent.setType(“video/*”); //选择视频 (mp4 3gp 是android支持的视频格式) //intent.setType(“video/;image/”);//同时选择视频和图片//文件选错intent.setType("image/*");startActivityForResult(intent,2);}//展示图片private void disPlayImage(String imagePath) {if (imagePath != null){Bitmap bitmap = BitmapFactory.decodeFile(imagePath);IVShowImage.setImageBitmap(bitmap);}else{Toast.makeText(this, "未能成功加载图片", Toast.LENGTH_SHORT).show();}}private String getImagePath(Uri uri, String Selection) {String path = null;//通过Uri和Selection来获取真实的图片路径Cursor cursor = getContentResolver().query(uri,null,Selection,null,null);Log.d(TAG, "cursor : "+cursor);//-> android.content.ContentResolver$CursorWrapperInner@6105cc6if (cursor!=null){// 查询得到的cursor是指向第一条记录之前的,因此查询得到cursor后第一次调用moveToFirst或moveToNext都可以将cursor移动到第一条if (cursor.moveToFirst()){Log.d(TAG, "getColumnIndex: "+cursor.getColumnIndex(MediaStore.Images.Media.DATA));  //17path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));}cursor.close();}Log.d(TAG, "getImagePath: "+path);// ->/storage/emulated/0/Download/R65398d6ad86129f9628c0ad80da4040c.jpegreturn path;}
}

Android拍照及从相册选择图片传详解(终极版)相关推荐

  1. Android 拍照、从相册选择图片

    在做Android图片上传功能的时候,获取图片的途径一般都有两种:拍照.从相册选择. 一.拍照 调用相机拍照有两种方法: 直接返回图片. 在调用相机的时候,传入uri,拍照后通过该uri来获取图片. ...

  2. Android6.0动态设置读写权限(Android拍照或从相册中选图片预览出现问题)

    做了一个Android拍照或从相册中选图片传服务器的demo,出现了问题虽然 图片路径 也可以打印出来,然后去看权限那里也申请了读写权限 <uses-permission android:nam ...

  3. android之跳转相册选择图片/照相

    使用环境: 跳转相册选择图片的时候,对于不同类型的图片有不同该类型的返回值: 这里说的就是vivo手机跳转相册返回的地址: 1 小米正常返回地址: file:///storage/emulated/0 ...

  4. pictureselector 压缩_Android 拍照、从相册选择图片之PictureSelector

    仿微信实现在Android平台下的图片选择器,支持从相册获取图片.视频.音频&拍照,支持裁剪(单图or多图裁剪).压缩.主题自定义配置等功能,支持动态获取权限&适配Android 5. ...

  5. Android10(华为Mate30)获取图片路径失败,拍照或从相册选择图片后无法显示

    在使用华为Mate30是从图库选择图片,本地无法显示,其他手机没问题,发现是兼容Android10的问题,Android10下本app的私有文件是不需要权限的,访问其他应用权限需要权限 android ...

  6. 兼容Android11的手机拍照上传图片和相册选择图片功能(可直接用)

    //需要的权限数组 读/写/相机 private static String[] PERMISSIONS_STORAGE = {android.Manifest.permission.READ_EXT ...

  7. jsx怎么往js里传参数_JSX语法使用详解——终极版

    一.基础 1.JSX是什么 JSX是一种像下面这样的语法: const element = Hello, world! ; 它是一种JavaScript语法扩展,在React中可以方便地用来描述UI. ...

  8. iOS上传头像, 相册权限,相册权限,拍照上传,相册选择图片,拍照页面语言设置,保存到相册...

    2019独角兽企业重金招聘Python工程师标准>>> 1. 权限 在打开相机拍照或者打开相册选择图片之前, 有必要先判断先是否有权限, 如果没有权限应该给个提示, 让用户自己去设置 ...

  9. MUI 拍照和从系统相册选择图片上传

    要完成用MUI 拍照和从系统相册选择图片上传的功能,可以理解成有三个功能 1 调用手机相机的功能(可以查看官方API  http://www.html5plus.org/doc/zh_cn/camer ...

最新文章

  1. C#的简单不安全双向“混淆”
  2. 已经了关联到svn的文件类型,如何添加到 ignore
  3. Spring boot 2.3优雅下线,距离生产还有多远?
  4. js中给多个class属性的标签赋值
  5. WinSock Socket 池
  6. 【100题】第十九题(斐波那楔数列)
  7. 活跃在海底隧道的铁路“小蓝人”
  8. 安卓模拟器genymotion连接eclipse成功但是不显示其中项目
  9. 转载如果在浏览器网页标题栏左侧加自定义小图标
  10. java 加载java文件_如何用JAVA实现加载一个文件?
  11. 5. COM编程——IDispatch介绍
  12. 删除任务管理器中的启动项
  13. 贝塔朗菲的一般系统论:系统的有序性和目的性
  14. sublime linux 中文 版,Linux 下 Sublime Text 3 中文输入 (Debian 系通用)
  15. Android破解九宫格密码
  16. android 向上滑动home,滑动Home键
  17. matlab三维曲线的绘制
  18. 如何找到一个网站的icon
  19. 服务器电源ic芯片,AC-DC适配器电源IC芯片方案选型表
  20. git基本概念以及简单用法

热门文章

  1. 查询网站的域名注册信息和备案信息
  2. 【RT-Thread开源作品秀】运动手表
  3. C#版 Socket编程(同步)
  4. 小白学习freemark的过程(代码全贴+详细介绍)
  5. 自制户外登山地图傻瓜书(转载)
  6. 国内大神成功给手机装上了Win11,支持一加、小米
  7. matlab函数结果,matlab 函数返回多个值--样例
  8. php json入门,JSON基础知识
  9. android 系统 keyboard 第一个字母是大写,「这个控件叫什么」系列之虚拟键盘/软键盘/Soft Keyboard...
  10. SPC58芯片的嵌入式开发准备工作-20201005