本文主要介紹保存圖片到相冊的幾種方式。其本質上并沒有把圖片保存到相冊中,實際上是保存在SD卡下自定義的文件夾中,目的只是讓QQ
和微信
在選擇照片的時候立刻顯示,注:其實QQ
和微信
也是這樣做的。
方式1-掃描文件通知相冊更新
// 通知相冊更新
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);
方式1-錯誤操作
MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), "name", "description");
// 通知相冊更新
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);
對比 方式1 和 錯誤方式 ,我們可以發現其實就是多了一行insertImage
的代碼,然后就不能被QQ
和微信
立刻識別了,好傷心~~
這里我稍微研究了一下,然而沒有發現本質原因,不過做了以下猜測,有興趣的可以自行研究源碼。
因為在使用ACTION_MEDIA_SCANNER_SCAN_FILE
方式通知相冊更新時,也需要執行類似insertImage
方法內部的某些操作,可能和ContentProvider
相關的數據庫有關,所以如果你先執行了insertImage
方法,那么它在接收到這個ACTION_MEDIA_SCANNER_SCAN_FILE
廣播的時候,做了如下判斷:如果已經執行了insertImage
方法,那么return;
,所以不會執行再通知相冊更新
了。
方式2-完整操作
// 插入file數據到相冊
ContentValues values = new ContentValues(9);
values.put(MediaStore.Images.Media.TITLE, "Camera");
values.put(MediaStore.Images.Media.DISPLAY_NAME, filename);
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
values.put(MediaStore.Images.Media.ORIENTATION, 0);
values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
values.put(MediaStore.Images.Media.SIZE, file.length());
Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
// 通知相冊更新
context.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri));
方式2-簡單操作
// 插入file數據到相冊
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
// 通知相冊更新
context.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri));
總結
對于Google
和百度
出來的Android保存圖片到相冊
表示無奈,90%以上都是一樣的,這個時候如果我們還是依靠搜索
,消耗的成本是很大的,如果你能夠從源碼
入手,可能就會給你提供一些思路,例如:上述所說的方式2
就是從insertImage
方法中得出的,源碼如下:
/**
* 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;
}