大家可能在用系统自带的Android插入图库方法:
MediaStore.Images.Media.insertImage in android.provider package of API 28
这个方法是系统提供给我们的插入图库的方法。先来看看它的源代码:
/**
* 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 null
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; /* 返回值 */
try {
url = cr.insert(EXTERNAL_CONTENT_URI, values);//将刚刚创建的ContentValues插入图库
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();//返回uri对应的字符串形式
}
return stringUrl;
}
概括一下就是这个流程:
1.从Context获取ContentResolver
2.新建ContentValues对象,设置其属性
3.将ContentValues对象插入数据库,并获得插入的Uri
4.通过Uri写入图片文件
5.返回Uri的字符串形式
1.图片被压缩
2.时间不正确,不能进入最近列表
被压缩问题很明显,在调用InsertImage方法时
try {
source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);//实际写入的图片
} finally {
imageOut.close();
}
已经以50质量的jpeg格式给你的bitmap压缩一遍了。
时间戳不正确,很明显是ContentValues缺少参数。
因此我去Android开发者文档去查了一下:链接
找到了几个有关于时间的字段:
DATE_ADDED
DATE_MODIFIED
DATE_TAKEN
还有一些有用的字段:
SIZE (解决图片大小问题)
WIDTH
HEIGHT
这些字段找全了插入图片就可以变得很简单了。
由于图片保存是在插入数据库之后,所以我们需要在插入数据库之前计算出文件的大小。因此考虑暂时将文件保存到内存中以计算图片文件大小:
ByteArrayOutputStream stream = new ByteArrayOutputStream(1920 * 1920);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
long size = stream.size();
stream.close();
最终我模拟了整个保存到图库的过程,流程如下:
1.保存图片到内存获取图片大小
2.创建ContentValues对象,设置DATA、DISPLAY_NAME、MIME_TYPE、DATE_ADDED、DATE_MODIFIED、DATE_TAKEN、SIZE、WIDTH、HEIGHT字段
3.使用resolver.insert将数据插入数据库并获取Uri
4.根据uri将图片数据写入文件
至于说网上很多人说要通知图库更新,没有必要,如果你没插入成功你怎么通知都是没有用的,如果你插入成功了打开图库你的图片就会在里面,图库更新会由系统自动完成,无须干预!
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
public class GalleryFileSaver {
public static final String PIC_DIR_NAME = "myPhotos"; //在系统的图片文件夹下创建了一个相册文件夹,名为“myPhotos",所有的图片都保存在该文件夹下。
private static File mPicDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), PIC_DIR_NAME); //图片统一保存在系统的图片文件夹中
public static Uri saveBitmapToGallery(final Context mContext, String fileName, Bitmap bitmap) {
OutputStream out = null;
try {
ByteArrayOutputStream stream = new ByteArrayOutputStream(1920 * 1920);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
long size = stream.size();
stream.close();
mPicDir.mkdirs();
String mPicPath = new File(mPicDir, fileName).getAbsolutePath();
ContentValues values = new ContentValues();
ContentResolver resolver = mContext.getContentResolver();
values.put(MediaStore.Images.ImageColumns.DATA, mPicPath);
values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
//将图片的拍摄时间设置为当前的时间
long current = System.currentTimeMillis() / 1000;
values.put(MediaStore.Images.ImageColumns.DATE_ADDED, current);
values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, current);
values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, current);
values.put(MediaStore.Images.ImageColumns.SIZE, size);
values.put(MediaStore.Images.ImageColumns.WIDTH, bitmap.getWidth());
values.put(MediaStore.Images.ImageColumns.HEIGHT, bitmap.getHeight());
Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
if (uri != null) {
out = resolver.openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
return uri;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}