如果我在我的sqlite数据库中存储了太多位图(如BLOB),在检索它们时我会遇到奇怪的异常(我甚至无法捕获它,但我每次都可以在LogCat中看到它):
Failed to read row 2, column 0 from a CursorWindow which has 2 rows, 8 columns
当我不存储BLOB时,我不会得到这样的例外。也许我应该将图像存储在手机内存中,并将数据库uris保存到这些图像中?
有什么问题?谁能告诉我?
答案 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);
}
你可以像上面给出的方法那样做。