可能大家都知道我们保存相册到Android手机的时候,然后去打开系统图库找不到我们想要的那张图片,那是因为我们插入的图片还没有更新的缘故,先讲解下插入系统图库的方法吧,很简单,一句代码就能实现
MediaStore.Images.Media.insertImage(getContentResolver(), mBitmap, "", "");
<span style="white-space:pre"> </span>/** * Insert an image and create a thumbnail for it. * * @param cr The content resolver to use * @param source The stream to use for the image * @param title The name of the image * @param description The description of the image * @return The URL to the newly created image, or <code>null</code> if the image failed to be stored * for any reason. */ public static final String insertImage(ContentResolver cr, Bitmap source, String title, String description) { ContentValues values = new ContentValues(); values.put(Images.Media.TITLE, title); values.put(Images.Media.DESCRIPTION, description); values.put(Images.Media.MIME_TYPE, "image/jpeg"); Uri url = null; String stringUrl = null; /* value to be returned */ try { url = cr.insert(EXTERNAL_CONTENT_URI, values); if (source != null) { OutputStream imageOut = cr.openOutputStream(url); try { source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut); } finally { imageOut.close(); } long id = ContentUris.parseId(url); // Wait until MINI_KIND thumbnail is generated. Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null); // This is for backward compatibility. Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND); } else { Log.e(TAG, "Failed to create thumbnail, removing original"); cr.delete(url, null, null); url = null; } } catch (Exception e) { Log.e(TAG, "Failed to insert image", e); if (url != null) { cr.delete(url, null, null); url = null; } } if (url != null) { stringUrl = url.toString(); } return stringUrl; }
当然Android还提供了一个插入系统相册的方法,可以指定保存图片的名字:
/** * Insert an image and create a thumbnail for it. * * @param cr The content resolver to use * @param imagePath The path to the image to insert * @param name The name of the image * @param description The description of the image * @return The URL to the newly created image * @throws FileNotFoundException */ public static final String insertImage(ContentResolver cr, String imagePath, String name, String description) throws FileNotFoundException { // Check if file exists with a FileInputStream FileInputStream stream = new FileInputStream(imagePath); try { Bitmap bm = BitmapFactory.decodeFile(imagePath); String ret = insertImage(cr, bm, name, description); bm.recycle(); return ret; } finally { try { stream.close(); } catch (IOException e) { } } }上面那段代码插入到系统相册之后还需要发条广播:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));这个广播在4.4 以上的手机会报错( 那是因为Android4.4中限制了系统应用才有权限使用广播通知系统扫描SD卡):
W/ActivityManager( 498): Permission Denial: not allowed to send broadcast android.intent.action.MEDIA_MOUNTED from pid=2269, uid=20016
解决方式:
使用MediaScannerConnection执行具体文件或文件夹进行扫描。
MediaScannerConnection.scanFile(this, new String[]{Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + "/" + fileName}, null, null);
<span style="white-space:pre"> </span>String url = MediaStore.Images.Media.insertImage(context.getContentResolver(), mBitmap, "", ""); // 4.4以上 Android 不允许发送 Intent.ACTION_MEDIA_MOUNTED // context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory() + url))); // 这个扫描指定文件,不能用于扫描文件夹 // context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory() + url))); MediaScannerConnection.scanFile(context, new String[]{FileUtil.getRealFilePath(context, Uri.parse(url))}, null, null);
/** * 将文件相对路径uri 转化为绝对路径 * content://media/external/images/media/62026 ===>> url * * @param context * @param uri * @return */ public static String getRealFilePath( final Context context, final Uri uri ) { if ( null == uri ) return null; final String scheme = uri.getScheme(); String data = null; if ( scheme == null ) data = uri.getPath(); else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) { data = uri.getPath(); } else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) { Cursor cursor = context.getContentResolver().query( uri, new String[] { MediaStore.Images.ImageColumns.DATA }, null, null, null ); if ( null != cursor ) { if ( cursor.moveToFirst() ) { int index = cursor.getColumnIndex( MediaStore.Images.ImageColumns.DATA ); if ( index > -1 ) { data = cursor.getString( index ); } } cursor.close(); } } return data; }
Context context = params[0].context; Bitmap image = params[0].image; Resources r = context.getResources(); try { // Create screenshot directory if it doesn't exist mScreenshotDir.mkdirs(); // media provider uses seconds for DATE_MODIFIED and DATE_ADDED, but milliseconds // for DATE_TAKEN long dateSeconds = mImageTime / 1000; // Save the screenshot to the MediaStore ContentValues values = new ContentValues(); ContentResolver resolver = context.getContentResolver(); values.put(MediaStore.Images.ImageColumns.DATA, mImageFilePath); values.put(MediaStore.Images.ImageColumns.TITLE, mImageFileName); values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, mImageFileName); values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, mImageTime); values.put(MediaStore.Images.ImageColumns.DATE_ADDED, dateSeconds); values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, dateSeconds); values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png"); values.put(MediaStore.Images.ImageColumns.WIDTH, mImageWidth); values.put(MediaStore.Images.ImageColumns.HEIGHT, mImageHeight); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); OutputStream out = resolver.openOutputStream(uri); image.compress(Bitmap.CompressFormat.PNG, 100, out); out.flush(); out.close(); // update file size in the database values.clear(); values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length()); resolver.update(uri, values, null, null); } catch (Exception e) { }
继续补充:
MediaStore.Images.Media.insertImage(getContentResolver(), mBitmap, "", "");
上面说的这个方法在本地相册路径不存在的时候 会抛出异常 FileNotFound ,当然这种情况下手机中不会存在,但是,市面上某些模拟器在没有拍过照片的情况下就会出现。 所以为了适配这种情况,换方法。
/** * 将图片保存至系统相册,并让系统刷新相册中的指定图片 * @param context * @param mBitmap */ public static String savePicToSystemGallery(Context context, Bitmap mBitmap){ // 这个insertImage 在本地相册路径不存在的时候回抛异常 : 例如天天模拟器 // String url = MediaStore.Images.Media.insertImage(context.getContentResolver(), mBitmap, "", ""); String url = PicUtil.saveBitmapToSDCard(System.currentTimeMillis() + "", mBitmap); // 4.4以上 Android 不允许发送 Intent.ACTION_MEDIA_MOUNTED // context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory() + url))); // 这个扫描指定文件,不能用于扫描文件夹 // context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment.getExternalStorageDirectory() + url))); MediaScannerConnection.scanFile(context, new String[]{FileUtil.getRealFilePath(context, Uri.parse(url))}, null, null); return url; }
public static String saveBitmapToSDCard(String picName, Bitmap bitmap) { try { File saveFile = new File(Environment.getExternalStorageDirectory().toString() + File.separator + PayConstants.KP_FOLDER_PATH + PayConstants.KP_SCREEN_SHOT_PATH + picName + ".png"); if (!saveFile.exists()) { File dir = new File(saveFile.getParent()); dir.mkdirs(); saveFile.createNewFile(); } FileOutputStream saveFileOutputStream; saveFileOutputStream = new FileOutputStream(saveFile); boolean nowbol = bitmap.compress(Bitmap.CompressFormat.PNG, 100, saveFileOutputStream); saveFileOutputStream.close(); if(nowbol) { return saveFile.getPath(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; }