Android应用保存图片到系统图库那些事儿
首先,手机Android应用对于图片的相关操作都是比较频繁的,比如大图浏览,图片编辑,图片压缩,图片上传等等,今儿我们要说的就是关于图片异步保存至手机相册,其他应用也能使用的一个小功能。
乍一看这个功能,可以分三步实现它,1.异步开启下载图片;2.拟定文件名,保存至文件夹中;3.通知系统广播,刷新数据。
核心代码如下所示:
Request mRequest = new Request.Builder()
.url(url)
.build();
Call mCall = new OkHttpClient().newCall(mRequest);
mCall.enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
showDialog(POSITION_FAIL);
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
byte[] bytes = response.body().bytes();
Bitmap mBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(mFile));
mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
MediaStore.Images.Media.insertImage(mContext.getContentResolver(),
mFile.getAbsolutePath(), mFile.getName(), null);
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + mFile.getPath())));
showDialog(POSITION_SUCCE);
}
});
这里是用的okhttp作为网络请求的框架,根据Response获取图片的Byte数组,利用BitmapFactory转化成Bitmap对象,然后写入File文件中,最后利用Intent广播数据库,刷新系统图库中的数据,从而达到保存本地的全部过程。这里有两点需要强调的是:第一,图片必须要保存在外部存储中,内部存储绝对不能考虑(1.应用一旦内存不够,就会销毁内部存储的文件;2.如果应用卸载内部存储中的数据会被全部删除;3.其他应用无法访问该文件夹,也就无法使用该图片);第二,必须要获取手机权限(动态处理),这不是本文的重点;1.
关于内部存储和外部存储,做如下解释:
第一.内部存储:(internal storage)
注意内部存储不是内存。内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他app能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared
Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。getFilesDir()获取你app的内部存储空间,相当于你的应用在内部存储上的根目录。
以下是常用的一些内部存储的api,以及对应的地址:
getCacheDir().getAbsolutePath()- - - - - - 》/data/data/packagename/cache
getFilesDir().getAbsolutePath()- - - - - - 》/data/data/packagename/files
getDataDir().getAbsolutePath()- - - - - - 》/data/data/packagename
第二.外部存储:(external storage)
最容易混淆的是外部存储,如果说pc上也要区分出外部存储和内部存储的话,那么自带的硬盘算是内部存储,U盘或者移动硬盘算是外部存储,因此我们很容易带着这样的理解去看待安卓手机,认为机身固有存储是内部存储,而扩展的T卡是外部存储。比如我们任务16GB版本的Nexus 4有16G的内部存储,普通消费者可以这样理解,但是安卓的编程中不能,这16GB仍然是外部存储。所有的安卓设备都有外部存储和内部存储,这两个名称来源于安卓的早期设备,那个时候的设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。但是在后来的设备中,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal"
和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储(外部存储)。外部存储虽然概念上有点复杂,但也很好区分,你把手机连接电脑,能被电脑识别的部分就一定是外部存储。
1.外部存储之公共文件:文件是可以被*访问,且文件的数据对其他应用或者用户来说都是由意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。比如camera应用,生成的照片大家都能访问,而且camera不在了,照片仍然在。如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()。
private File getFile(String fileName)
{
File mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), fileName);
if (!mFile.exists())
{
mFile.mkdirs();
}
return mFile;
}
private File getFile(String fileName)
{
File mFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
return mFile;
}
所有应用程序的外部存储的私有文件都放在根目录的Android/data/下,目录形式为/Android/data/<package_name>/ 在使用外部存储之前,你必须要先检查外部存储的当前状态,以判断是否可用。String mState = Environment.getExternalStorageState();
if (mState.equals(Environment.MEDIA_MOUNTED))
{
//We can read and write file
}
总的来说,一些小的功能可以看出一位码匠的基础,基础越牢固,效率越高。祝大家工作顺利,生活开心。