版权声明:本文为博主原创文章,未经博主允许不得转载。
由于最近开发的一款app需要调用系统的照相机功能和获取相册中图片,在做手机版本适配7.0适配的时候,遇到一个大坑,拍照之后的照片,从相册中获取不到,最后Debug测试才知道获取的uri路径不对,最后使用Fileprovider解决问题.这里还讲图片进行了压缩的处理,这样更加节省性能的消耗!!!!!!!!!!
废话不多说了直接上代码,如需要完整的代码可以在我的github上下载,地址如下:
https://github.com/HelloWmz/PhotoDemo
使用Fileprovider之前需要在mainfest文件中配置配置如下:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="applicationId.fileprovider" android:exported="false" android:grantUriPermissions="true" > <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> provider>
这里依赖的是v4包下的FileProvider
applicationId.fileprovider 配置这个属性的时候要与
FileProvider.getUriForFile(this, "applicationId.fileprovider", photoFile);方法中的要一直可以随意写
@xml/file_paths需要在res\xml\file_paths创建代码如下:
xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path path="" name="camera_photos" /> <external-path name="my_images" path="Android/data/com.example.wmz.network/files/Pictures/" /> <external-path name="images" path="Pictures/" /> <external-path name="dcim" path="DCIM/" /> paths>
所以这篇文章写下自己当时遇到的坑,完整代码如下:
public class PhotoActivity extends Activity implements View.OnClickListener { public Button mButton; public Button mButtonPic; public ImageView mImageView; //临时文件 private String mPublicPhotoPath; private String path; private Uri uri; private static final int REQ_GALLERY = 333; private static final int REQUEST_CODE_PICK_IMAGE = 222; public int mWidth; public int mHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_photo); initView(); } private void initView() { mButton = ((Button) findViewById(R.id.bt)); mButtonPic = ((Button) findViewById(R.id.btpic)); mImageView = ((ImageView) findViewById(R.id.iv)); mButton.setOnClickListener(this); mButtonPic.setOnClickListener(this); } //当点击bt的时候将获取系统的拍照功能,必将拍照之后的照片显示在ImageView中 @Override public void onClick(View v) { switch (v.getId()){ case R.id.bt: //获取拍照的权限 showTakePicture(); break; case R.id.btpic: //获取相册中的照片 getImageFromAlbum(); break; } }
###这里使用的是第三方的框架动态的申请权限依赖这个库就行,用法很简单就不多去讲解了
compile 'com.lovedise:permissiongen:0.0.6'
//获取拍照的权限 private void showTakePicture() { PermissionGen.with(PhotoActivity.this) .addRequestCode(100) .permissions( Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE ) .request(); } //权限申请的回调 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults); } //权限申请成功的回调 @PermissionSuccess(requestCode = 100) public void doSomething() { //开启拍照功能 startTake(); } @PermissionFail(requestCode = 100) public void doFailSomething() { //权限申请失败的处理 } private void startTake() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //判断是否有相机应用 if (takePictureIntent.resolveActivity(getPackageManager()) != null) { //创建临时图片文件 File photoFile = null; try { photoFile = createPublicImageFile(); } catch (IOException e) { e.printStackTrace(); } //设置Action为拍照 if (photoFile != null) { takePictureIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); //这里加入flag takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri photoURI = FileProvider.getUriForFile(this, "applicationId.fileprovider", photoFile); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI); startActivityForResult(takePictureIntent, REQ_GALLERY); } } //将照片添加到相册中 galleryAddPic(mPublicPhotoPath, this); } /** * 获取相册中的图片 */ public void getImageFromAlbum() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/*");//相片类型 startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE); } /** * 创建临时图片文件 * * @return * @throws IOException */ private File createPublicImageFile() throws IOException { File path = null; if (hasSdcard()) { path = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DCIM); } Date date = new Date(); String timeStamp = getTime(date, "yyyyMMdd_HHmmss", Locale.CHINA); String imageFileName = "Camera/" + "IMG_" + timeStamp + ".jpg"; File image = new File(path, imageFileName); mPublicPhotoPath = image.getAbsolutePath(); return image; } /** * 判断sdcard是否被挂载 * * @return */ public static boolean hasSdcard() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { return true; } else { return false; } } /** * 获取时间的方法 * @param date * @param mode * @param locale * @return */ private String getTime(Date date, String mode, Locale locale) { SimpleDateFormat format = new SimpleDateFormat(mode, locale); return format.format(date); } /** * 将照片添加到相册中 */ public static void galleryAddPic(String mPublicPhotoPath, Context context) { Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); File f = new File(mPublicPhotoPath); Uri contentUri = Uri.fromFile(f); mediaScanIntent.setData(contentUri); context.sendBroadcast(mediaScanIntent); } /** * 拍照之后获取结果的方法 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); //获取mImageView的宽高 mWidth = mImageView.getWidth(); mHeight = mImageView.getHeight(); switch (requestCode) { //拍照 case REQ_GALLERY: if (resultCode != Activity.RESULT_OK) return; uri = Uri.parse(mPublicPhotoPath); path = uri.getPath(); break; //获取相册的图片 case REQUEST_CODE_PICK_IMAGE: if (data == null) return; uri = data.getData(); int sdkVersion = Integer.valueOf(Build.VERSION.SDK); if (sdkVersion >= 19) { // 或者 android.os.Build.VERSION_CODES.KITKAT这个常量的值是19 path = this.uri.getPath();//5.0直接返回的是图片路径 Uri.getPath is : /document/image:46 ,5.0以下是一个和数据库有关的索引值 // path_above19:/storage/emulated/0/girl.jpg 这里才是获取的图片的真实路径 path =getPath_above19(PhotoActivity.this, this.uri); } else { path = getFilePath_below19(PhotoActivity.this, this.uri); } break; } mImageView.setImageBitmap(getSmallBitmap(path, mWidth, mHeight)); } /** * 获取小于api19时获取相册中图片真正的uri * @param context * @param uri * @return */ public static String getFilePath_below19(Context context,Uri uri) { //这里开始的第二部分,获取图片的路径:低版本的是没问题的,但是sdk>19会获取不到 String[] proj = {MediaStore.Images.Media.DATA}; //好像是android多媒体数据库的封装接口,具体的看Android文档 Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); //获得用户选择的图片的索引值 int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); //将光标移至开头 ,这个很重要,不小心很容易引起越界 cursor.moveToFirst(); //最后根据索引值获取图片路径 结果类似:/mnt/sdcard/DCIM/Camera/IMG_20151124_013332.jpg String path = cursor.getString(column_index); return path; } /** * 获取大于api19时获取相册中图片真正的uri * @param context * @param uri * @return */ @TargetApi(Build.VERSION_CODES.KITKAT) public static String getPath_above19(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { // ExternalStorageProvider if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { return Environment.getExternalStorageDirectory() + "/" + split[1]; } } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{ split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { // Return the remote address if (isGooglePhotosUri(uri)) return uri.getLastPathSegment(); return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { Cursor cursor = null; final String column = "_data"; final String[] projection = {column}; try { cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); if (cursor != null && cursor.moveToFirst()) { final int index = cursor.getColumnIndexOrThrow(column); return cursor.getString(index); } } finally { if (cursor != null) cursor.close(); } return null; } public static boolean isExternalStorageDocument(Uri uri) { return "com.android.externalstorage.documents".equals(uri.getAuthority()); } public static boolean isDownloadsDocument(Uri uri) { return "com.android.providers.downloads.documents".equals(uri.getAuthority()); } public static boolean isMediaDocument(Uri uri) { return "com.android.providers.media.documents".equals(uri.getAuthority()); } public static boolean isGooglePhotosUri(Uri uri) { return "com.google.android.apps.photos.content".equals(uri.getAuthority()); } /** * 图片的压缩 * @param options * @param reqWidth * @param reqHeight * @return */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; } /** * 根据路径获得突破并压缩返回bitmap用于显示 * @param filePath * @return */ public static Bitmap getSmallBitmap(String filePath, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); //只返回图片的大小信息 options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; return BitmapFactory.decodeFile(filePath, options); }}
这样就可以完美的解决此bug,这里我做了在给imageView添加图片之前先做了压缩的处理.希望这篇文章对你有所帮助,下次有时间将
写写沉浸式状态栏的文章,能顶一个!!!!!!!!