最近在做项目的时候有一个需求,是要从相机中或相册中获取图片,而且还要将其存入SQLite,最开始的时候我想的是直接将图片存入数据库,但是后来在Google上发现不行,sqlite不支持这种类型,但是我看到了它支持Blob这种类型,也就是二进制,这种类型可以储存图片和视频,既然最基本的储存解决了,那么就开始动手写代码了。
直接用模板代码调用相机和相册
调用相机和相册是有模板代码的,可以考虑以后把它写成一个自己的库,方便以后的项目中调用。其大致思路就是:
- 确定好图片名称,由于图片名称肯定不能重复,所以这里直接用当前时间加上后缀来命名。
- 获取File路径,创建File对象,也就是你要将图片放在哪。
- 将File对象转换为Uri对象。
- 利用Intent放入要执行的动作,这里从相册选取和拍照选取图片有所不同。
- startActivityForResult直接启动Intent,在onActivityResult 接受数据。
- 通过requestCode判断是拍照还是打开相册。
- 如果是拍照就准备Intent启动裁剪工作,依然是使用startActivityForResult来启动裁剪程序获得图片,从相册选取得到照片也是一样的。
- 最后将图片转换为Byte[]类型,存入数据库。
- 刷新UI ,展示获得的图片。
1 | //此为启动相机 |
1 | //此为启动相册 |
1 | @Override |
1 | private void addNewCard() |
问题的发生及解决
当然不会这么一帆风顺,在调试app时发现从相册取出图片可以正常工作,但是调用相机拍照时,裁剪完毕点击确定时,app进入黑屏状态,停留10多秒后直接闪退,待我马上再次点开app时系统报错。
1 | 01-29 13:41:56.520: W/CursorWindow(4121): Window is full: requested allocation 5140987 bytes, free space 2096617 bytes, window size 2097152 bytes |
这是什么?从来没有见过这种报错,不过CursorWindow倒是给我提醒可能是数据库的问题,我不信邪,就卸了app重新运行,这次发现从相册选取照片也是有事行有时不行,我还没有遇到过这么怪的事,于是我就把上段报错信息google了一下,马上就在StackoverFlow上找到了答案,里面有一个和我一模一样的问题,下面已有人解决了:
原来是数据库的读取中出现了问题,Cursor对象只能够存储1MB的数据(网上有人说是1MB,我验证了一下,好像确实是1MB),多了会发生这样的报错。为了验证这个原因,我想之前从相册选取照片有时成功有时失败的问题,我猜想可能是选取了大于1MB的图片和小于1MB的图片的问题,为了验证这个猜想我准备了两张不同大小的照片,果然在选取小的那张时就成功了,大的系统就崩溃了。
现在问题已经找出来了,那么在我面前有两条路。
- 重新设计数据库结构,改直接储存图片为间接储存图片的Uri地址。
- 不用改变数据库结构,将图片压缩至1MB内,存入数据库。
两种方法各有好处,第一种方法的好处是数据库本就不适合储存数据大的文件,间接储存可以提高数据库读写效率。但是坏处是数据的整体性不强,如果用户在手机里把图片删了,那么从数据库里读取就会报错,而且对于我现在来说代码改动太大了,不利于维护;第二种方法的好处是整体性强,直接存入数据库,就算用户在手机里删除了图片,也不怕,数据库里还有。但是相应的效率就会下降。
我当即决定采用第二种方法,我实在是不想动代码太多了,但是我又不懂图片压缩算法,不可能去现学吧。于是我马上想到了Github这个牛人云集的地方,我在github搜索“Android Compress”于是马上就有写好的库给我调用了。在这里再次感谢
https://github.com/zetbaitsu/Compressor
提供的图片压缩算法。
好了仅仅只需要一行代码就可以压缩图片了bitmap= tool.ImageUtil.getScaledBitmap(this, imgUri, 612.0f, 816.0f);
但是最开始这个库并没有给我提供Uri转Bitmap的方法,而是只有File转Bitmap,我不信这个邪,于是我点进源代码看。
1 | public Bitmap compressToBitmap(File file) { |
原来是调用了ImageUtil.getScaledBitmap方法,而这个方法是调用的uri,之不过多了一个将File转化为Uri的过程,但是我现在不需要这个过程怎么办呢?于是我机智的修改了下源代码为我所用,那么一切都OK了。
最后运行程序,不管是相册还是相机都运行得很好了。
反思总结
今天的这个找bug我收益良多,总结起来就是,注意报错信息,利用好Google,Stackoverflow,并注意多调试验证从网上看到的答案。