在Sqlite中将位图存储为BLOB是个好主意吗?

时间:2015-09-14 20:03:43

标签: android sqlite bitmap

如果我在我的sqlite数据库中存储了太多位图(如BLOB),在检索它们时我会遇到奇怪的异常(我甚至无法捕获它,但我每次都可以在LogCat中看到它):

Failed to read row 2, column 0 from a CursorWindow which has 2 rows, 8 columns

当我不存储BLOB时,我不会得到这样的例外。也许我应该将图像存储在手机内存中,并将数据库uris保存到这些图像中?

有什么问题?谁能告诉我?

2 个答案:

答案 0 :(得分:3)

通常,在您的数据库中存储位图/图像通常不是一个好主意,它根本没有效率。

您应该将位图保存为图像并将路径存储在数据库中。

这在this question上进行了讨论。

修改

但是......如果你因为某种原因真的要存储它,你也可以尝试将图像编码为Base64 String,并将其存储在你的数据库中。

Android为此提供了Base64 class。尝试使用以下代码段进行编码:

ByteArrayOutputStream baos = new ByteArrayOutputStream();  
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); // Could be Bitmap.CompressFormat.PNG or Bitmap.CompressFormat.WEBP
byte[] bai = baos.toByteArray();

String base64Image = Base64.encodeToString(bai, Base64.DEFAULT);

// Call your method to save this string on the DB here.

你必须解码它,尝试以下方法:

byte[] data = Base64.decode(base64Image, Base64.DEFAULT);
Bitmap bm;
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
bm = BitmapFactory.decodeByteArray(data, 0, data.length, opt);

// Now do whatever you want with the Bitmap.

您可以查看Bitmap课程here的文档。

答案 1 :(得分:1)

  profile_images.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {


    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
                photoPickerIntent.setType("image/*");
                startActivityForResult(photoPickerIntent, SELECT_PHOTO);

            }
        });


  protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
        super.onActivityResult(requestCode, resultCode, imageReturnedIntent);

        switch(requestCode) {
            case SELECT_PHOTO:
                if(resultCode == RESULT_OK){
                    Uri selectedImage = imageReturnedIntent.getData();
                    try {
                        Bitmap bmp = decodeUri(selectedImage);
                        profile_images.setImageBitmap(bmp);
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
                        bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                        byte[] byteArray = stream.toByteArray();

                        insertUser(byteArray);

                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
        }
    }
public void insertUser(byte[] logoImage ){
    SQLiteDatabase db               =   dbs.getWritableDatabase();

    String delSql                       =   "DELETE FROM Image";
    SQLiteStatement delStmt         =   db.compileStatement(delSql);
    delStmt.execute();

    String sql                      =   "INSERT INTO Image (CODE,Img) VALUES(?,?)";
    SQLiteStatement insertStmt      =   db.compileStatement(sql);
    insertStmt.clearBindings();
    insertStmt.bindLong(1, 1);
    insertStmt.bindBlob(2,logoImage);
    //   insertStmt.bindBlob(3, this.accImage);
    insertStmt.executeInsert();
    db.close();
}



  public Bitmap getCurrentBitmap() {
        SQLiteDatabase db       =   dbs.getWritableDatabase();
        String sql              =   "SELECT * FROM Image";
        Cursor cursor           =   db.rawQuery(sql, new String[]{});
        Bitmap bmp=null;
        if(cursor.moveToFirst()){
            //this.accId             = cursor.getInt(0);
            //  this.accName           = cursor.getString(1);
            byte[] logoImage       = cursor.getBlob(1);

            bmp = BitmapFactory.decodeByteArray(logoImage, 0, logoImage.length);
        }
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        db.close();
        if(cursor.getCount() == 0){
            return null;
        } else {
            return bmp;
        }
    }


    private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 140;
    // Find the correct scale value. It should be the power of 2.
    int width_tmp = o.outWidth, height_tmp = o.outHeight;
    int scale = 1;
    while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE
                || height_tmp / 2 < REQUIRED_SIZE) {
            break;
        }
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
    }

    // Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

}

你可以像上面给出的方法那样做。