Android调用相机和相册获取图片并存入数据库

最近在做项目的时候有一个需求,是要从相机中或相册中获取图片,而且还要将其存入SQLite,最开始的时候我想的是直接将图片存入数据库,但是后来在Google上发现不行,sqlite不支持这种类型,但是我看到了它支持Blob这种类型,也就是二进制,这种类型可以储存图片和视频,既然最基本的储存解决了,那么就开始动手写代码了。


直接用模板代码调用相机和相册

调用相机和相册是有模板代码的,可以考虑以后把它写成一个自己的库,方便以后的项目中调用。其大致思路就是:

  1. 确定好图片名称,由于图片名称肯定不能重复,所以这里直接用当前时间加上后缀来命名。
  2. 获取File路径,创建File对象,也就是你要将图片放在哪。
  3. 将File对象转换为Uri对象。
  4. 利用Intent放入要执行的动作,这里从相册选取和拍照选取图片有所不同。
  5. startActivityForResult直接启动Intent,在onActivityResult 接受数据。
  6. 通过requestCode判断是拍照还是打开相册。
  7. 如果是拍照就准备Intent启动裁剪工作,依然是使用startActivityForResult来启动裁剪程序获得图片,从相册选取得到照片也是一样的。
  8. 最后将图片转换为Byte[]类型,存入数据库。
  9. 刷新UI ,展示获得的图片。
//此为启动相机
takePhotoButton.setOnClickListener(new View.OnClickListener()
                {
                    @Override
                    public void onClick(View v)
                    {
                        String photoName = bean.getDateInfo() + "_image.jpg";
                        Log.d("haha", "photoName is " + photoName);
                        outputImage = new File(Environment.getExternalStorageDirectory()+"/ASimpleCount/", photoName);
                        try
                        {
                            if(outputImage.exists())
                            {
                                outputImage.delete();
                            }
                            outputImage.createNewFile();
                            Log.d("haha", "创建图片存储目录");
                        } catch (IOException e)
                        {
                            Log.d("haha", "创建目录抛出异常");
                            e.printStackTrace();
                        }
                        imageUri = Uri.fromFile(outputImage);//将文件路径转化为Uri对象
                        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                        intent.putExtra("name", bean.getName());
                        startActivityForResult(intent,TAKE_PHOTO);
                        materialDialog.dismiss();
                    }
                });
//此为启动相册
chooseGalleryButton.setOnClickListener(new View.OnClickListener()//选择从相册选择相片
                {
                    @Override
                    public void onClick(View v)
                    {
                        String photoName = bean.getDateInfo() + "_image.jpg";
                        outputImage = new File(Environment.getExternalStorageDirectory()+ "/ASimpleCount/", photoName);
                        try
                        {
                            if(outputImage.exists())
                            {
                                outputImage.delete();
                            }
                            outputImage.createNewFile();
                        } catch (IOException e)
                        {
                            e.printStackTrace();
                        }
                        imageUri = Uri.fromFile(outputImage);//将文件路径转化为Uri对象
                        Intent intent = new Intent(Intent.ACTION_PICK);
                        intent.setType("image/*");
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                        intent.putExtra("name", bean.getName());
                        startActivityForResult(intent, CHOOSE_PHOTO);
                        materialDialog.dismiss();
                    }
                });

            }
        });
 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
            case TAKE_PHOTO:
                    if(resultCode==RESULT_OK)
                    {
                        Intent intent = new Intent("com.android.camera.action.CROP");
                        intent.setDataAndType(imageUri, "image/*");
                        intent.putExtra("scale", true);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                        startActivityForResult(intent,CROP_PHOTO);
                    }
                break;
            case CROP_PHOTO:
                    if (resultCode == RESULT_OK)
                    {
                            bitmap = Compressor.getDefault(this).compressToBitmap(outputImage);
                            bean.setPicInfo(BitmapHandler.convertBitmapToByte(bitmap));
                            /**
                             * 数据获取完毕,增加卡片
                             */
                            addNewCard();
                    }
                break;
            case CHOOSE_PHOTO:
                ContentResolver resolver = getContentResolver();
                Uri imgUri = data.getData();
//                try
//                {
//                    bitmap = MediaStore.Images.Media.getBitmap(resolver,
//                            imgUri);
                    bitmap= tool.ImageUtil.getScaledBitmap(this, imgUri, 612.0f,  816.0f);
                    bean.setPicInfo(BitmapHandler.convertBitmapToByte(bitmap));
//                } catch (IOException e)
//                {
//                    e.printStackTrace();
//                }
                addNewCard();
                break;
        }
    }
 private void addNewCard()
    {
        saveBeanToDataBase();
        Log.d("haha", "在addcard方法中"+bean.toString());
        showRecyclerView();
    }

问题的发生及解决

当然不会这么一帆风顺,在调试app时发现从相册取出图片可以正常工作,但是调用相机拍照时,裁剪完毕点击确定时,app进入黑屏状态,停留10多秒后直接闪退,待我马上再次点开app时系统报错。

01-29 13:41:56.520: W/CursorWindow(4121): Window is full: requested allocation 5140987 bytes, free space 2096617 bytes, window size 2097152 bytes
01-29 13:41:56.520: E/CursorWindow(4121): Failed to read row 0, column 0 from a CursorWindow which has 0 rows, 9 columns.

01-29 13:43:30.932: W/System.err(4121): java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it. 
01-29 13:43:30.932: W/System.err(4121):     at android.database.CursorWindow.nativeGetLong(Native Method) 

这是什么?从来没有见过这种报错,不过CursorWindow倒是给我提醒可能是数据库的问题,我不信邪,就卸了app重新运行,这次发现从相册选取照片也是有事行有时不行,我还没有遇到过这么怪的事,于是我就把上段报错信息google了一下,马上就在StackoverFlow上找到了答案,里面有一个和我一模一样的问题,下面已有人解决了:

http://stackoverflow.com/questions/21432556/android-java-lang-illegalstateexception-couldnt-read-row-0-col-0-from-cursorw

这里写图片描述

原来是数据库的读取中出现了问题,Cursor对象只能够存储1MB的数据(网上有人说是1MB,我验证了一下,好像确实是1MB),多了会发生这样的报错。为了验证这个原因,我想之前从相册选取照片有时成功有时失败的问题,我猜想可能是选取了大于1MB的图片和小于1MB的图片的问题,为了验证这个猜想我准备了两张不同大小的照片,果然在选取小的那张时就成功了,大的系统就崩溃了。

 现在问题已经找出来了,那么在我面前有两条路。
  1. 重新设计数据库结构,改直接储存图片为间接储存图片的Uri地址。

  2. 不用改变数据库结构,将图片压缩至1MB内,存入数据库。

    两种方法各有好处,第一种方法的好处是数据库本就不适合储存数据大的文件,间接储存可以提高数据库读写效率。但是坏处是数据的整体性不强,如果用户在手机里把图片删了,那么从数据库里读取就会报错,而且对于我现在来说代码改动太大了,不利于维护;第二种方法的好处是整体性强,直接存入数据库,就算用户在手机里删除了图片,也不怕,数据库里还有。但是相应的效率就会下降。
    

    我当即决定采用第二种方法,我实在是不想动代码太多了,但是我又不懂图片压缩算法,不可能去现学吧。于是我马上想到了Github这个牛人云集的地方,我在github搜索“Android Compress”于是马上就有写好的库给我调用了。在这里再次感谢

https://github.com/zetbaitsu/Compressor
提供的图片压缩算法。
好了仅仅只需要一行代码就可以压缩图片了bitmap= tool.ImageUtil.getScaledBitmap(this, imgUri, 612.0f, 816.0f); 但是最开始这个库并没有给我提供Uri转Bitmap的方法,而是只有File转Bitmap,我不信这个邪,于是我点进源代码看。

 public Bitmap compressToBitmap(File file) {
        return ImageUtil.getScaledBitmap(context, Uri.fromFile(file), maxWidth, maxHeight);
    }

原来是调用了ImageUtil.getScaledBitmap方法,而这个方法是调用的uri,之不过多了一个将File转化为Uri的过程,但是我现在不需要这个过程怎么办呢?于是我机智的修改了下源代码为我所用,那么一切都OK了。

  最后运行程序,不管是相册还是相机都运行得很好了。

反思总结

今天的这个找bug我收益良多,总结起来就是,注意报错信息,利用好Google,Stackoverflow,并注意多调试验证从网上看到的答案。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,049评论 25 707
  • 本篇主要对Android调用系统相机裁剪及适配Android N的总结,不习惯简书代码风格的,也可以在 Andro...
    Showdy阅读 9,443评论 9 34
  • 红眼的狐狸高举赤旗 白眼的豺狼逃向南方 他们都饿了很久 他们也咬了很久 泥腿子拔出土地 在狐狸的赤旗下 在人民的名...
    回车李阅读 406评论 0 2
  • 对于想租房子的人,有个天大的的问题:如何快速租房?租房的途径有不少,现在无论是互联网还是中介,手中的房源都很多,但...
    易语天辰阅读 485评论 0 2
  • 不由自主推开窗 旧时光已经爬到云上 谁的唠叨又在耳边回响 空气里弥漫着韭菜香 比红玫瑰还要芬芳 有片绿叶独自在异乡...
    醒骨真人阅读 229评论 0 1