直接调用系统方法MediaStore类实现
需要图片路径和名称
/** * 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) { } } }
需要图片bitmap值和图片名称
/** * 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; }
上面两种方式理论上都是可行的,但是有一个问题,就是这两种方式在真正执行插入动作时,需要把固定路径下的图片首先转为bitmap,然后给到ContentResolver的OutputStream。 这样导致的问题就是。如果是小图片没问题,但是如果是比较大的图,在图片转bitmap过程中会非常大概率出现OOM.
Bitmap bm = BitmapFactory.decodeFile(imagePath);
换个思路,如果通过文件流方式写入ContentResolver的OutputStream,转Bitmap过程的OOM应该会解决
改写系统方法
/**
* 保存图片到相册
*
* @param filePath The path to the image to insert
* @param name The name of the image
* @return 图片是否成功插入到相册
* @throws FileNotFoundException
*/
public static boolean saveImage2Gallery(Context context, String filePath, String fileName) throws IOException {
if (context == null || fileName == null || filePath == null) {
Log.e(TAG, "saveImage2Gallery: context: " + context + ",filePath: " + filePath + ",fileName: " + fileName);
return false;
}
File file = new File(filePath, fileName);
if (!file.exists()) {
throw new FileNotFoundException();
}
if (isPicMedia(fileName)) {
ContentResolver contentResolver = context.getContentResolver();
//向多媒体数据库中插入一条记录
ContentValues values = new ContentValues(3);
values.put(MediaStore.Images.Media.TITLE, "");
values.put(MediaStore.Images.Media.DESCRIPTION, "");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri url = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
//查询新创建记录的id
if (url != null) {
long id = ContentUris.parseId(url);
OutputStream outputStream = null;
FileInputStream fileInputStream = null;
try {
outputStream = contentResolver.openOutputStream(url);
//向uri中写图片数据
fileInputStream = new FileInputStream(new File(filePath, fileName));
byte[] buffer = new byte[1024 * 5];
int len;
while ((len = fileInputStream.read(buffer)) != -1) {
if (outputStream != null) {
outputStream.write(buffer, 0, len);
}
}
} catch (IOException e) {
e.printStackTrace();
throw new IOException();
} finally {
try {
if (outputStream != null) {
outputStream.close();
}
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//生成缩略图
Bitmap miniThumb = MediaStore.Images.Thumbnails.getThumbnail(contentResolver, id,
MediaStore.Images.Thumbnails.MINI_KIND, null);
//将缩略图插入到数据库(MediaStore类内部private方法,可copy出来)
Bitmap microThumb = StoreThumbnail(contentResolver, miniThumb, id, 50F, 50F,
MediaStore.Images.Thumbnails.MICRO_KIND);
//插入相册成功后把原路径图片删除
FileUtil.deleteFile(new File(filePath, fileName));
String realPath = getFilePathFromContentUri(url, contentResolver);
if(!TextUtils.isEmpty(realPath)) {
//通知系统更新此文件
Timber.i("插入相册后的路径------>"+realPath);
File insertFile = new File(realPath);
notifyMediaFileScan(context, insertFile.getParent(), insertFile.getName());
}
return true;
}
return false;
} else {
Log.e(TAG, "saveImage2Gallery: file type error. fileName : " + fileName);
return false;
}
}
/**
* Gets the corresponding path to a file from the given content:// URI
* @param selectedVideoUri The content:// URI to find the file path from
* @param contentResolver The content resolver to use to perform the query.
* @return the file path as a string
*/
public static String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePath;
String[] filePathColumn = {MediaStore.MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
//也可用下面的方法拿到cursor
//Cursor cursor = this.context.managedQuery(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
//通知系统文件改动
public static void notifyMediaFileScan(Context context, String path, String fileName) {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(path, fileName))));
}
附网上说的比较多的通知图库刷新方法
// 通知图库更新(路径)
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + path)));
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File("/sdcard/Boohee/image.jpg"))););
不加载图片的前提下获得图片的宽高(防止为得到图片宽高而加载到内存的浪费)
BitmapFactory.Options options = new BitmapFactory.Options();
/**
* 最关键在此,把options.inJustDecodeBounds = true;
* 这里再decodeFile(),返回的bitmap为空,但此时调用options.outHeight时,已经包含了图片的高了
*/
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg", options); // 此时返回的bitmap为null
/**
*options.outHeight为原始图片的高
*/
Log.e("Test", "Bitmap Height == " + options.outHeight);