检索 blob 时 SQLite 数据库中的异常
Posted
技术标签:
【中文标题】检索 blob 时 SQLite 数据库中的异常【英文标题】:Exception in SQLite Database while retrieving a blob 【发布时间】:2021-06-29 06:04:12 【问题描述】:我创建了一个订单表,以显示购物车中的商品。当我单击产品详细信息活动中的添加到购物车按钮时,应用程序崩溃并转到上一页。但是,我可以在列表视图中看到购物车项目。
OrderProvider 类:
public class OrderProvider extends ContentProvider
// this constant is needed in order to define the path of our modification in the table
public static final int ORDER=100;
public DBHelper mhelper;
public static UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static
sUriMatcher.addURI(OrderContract.CONTENT_AUTHORITY,OrderContract.PATH,ORDER);
@Override
public boolean onCreate()
mhelper = new DBHelper(getContext());
return true;
@Override
public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
SQLiteDatabase database = mhelper.getReadableDatabase();
Cursor cursor;
int match = sUriMatcher.match(uri);
switch (match)
case ORDER:
cursor = database.query(OrderContract.OrderEntry.TABLE_NAME, projection, selection, selectionArgs, null,null, sortOrder);
break;
default:
throw new IllegalArgumentException("CANT QUERY");
cursor.setNotificationUri(getContext().getContentResolver(),uri);
return cursor;
@Override
public String getType(Uri uri)
return null;
@Override
public Uri insert(Uri uri, ContentValues values)
int match = sUriMatcher.match(uri);
switch (match)
case ORDER:
return insertCart(uri, values);
default:
throw new IllegalArgumentException("Cant insert data");
private Uri insertCart(Uri uri, ContentValues values)
String name = values.getAsString(OrderContract.OrderEntry.COLUMN_NAME);
if(name == null)
throw new IllegalArgumentException("Name is Required");
String quantity = values.getAsString(OrderContract.OrderEntry.COLUMN_QUANTITY);
if(quantity == null)
throw new IllegalArgumentException("Quantity is Required");
String price = values.getAsString(OrderContract.OrderEntry.COLUMN_PRICE);
if(price == null)
throw new IllegalArgumentException("Price is Required");
byte[] image = values.getAsByteArray(OrderContract.OrderEntry.COLUMN_IMAGE);
if(image == null)
throw new IllegalArgumentException("Image is Required"); //shows this error in logcat
//insert values into order
SQLiteDatabase database = mhelper.getWritableDatabase();
long id = database.insert(OrderContract.OrderEntry.TABLE_NAME, null, values);
if(id == 0)
return null;
getContext().getContentResolver().notifyChange(uri,null);
return ContentUris.withAppendedId(uri,id);
@Override
public int delete(Uri uri, String selection, String[] selectionArgs)
//delete data once order is made
int rowsDeleted;
SQLiteDatabase database = mhelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
switch (match)
case ORDER:
rowsDeleted = database.delete(OrderContract.OrderEntry.TABLE_NAME, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Cannot delete");
if (rowsDeleted!=0)
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
return 0;
OrderContract.class:
public class OrderContract
public OrderContract()
//content authority requires package name
public static final String CONTENT_AUTHORITY = "com.example.myapp";
public static final Uri BASE_URI = Uri.parse(("content://" +CONTENT_AUTHORITY));
//same as table name
public static final String PATH = "orders" ;
public static abstract class OrderEntry implements BaseColumns
public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_URI,PATH);
public static final String TABLE_NAME = "orders" ;
public static final String _ID = BaseColumns._ID ;
public static final String COLUMN_NAME = "name" ;
public static final String COLUMN_QUANTITY = "quantity" ;
public static final String COLUMN_PRICE = "price" ;
public static final String COLUMN_IMAGE = "image" ;
ProductDetails.class:
public class Sofa1 extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>
ImageButton plusquantity,minusquantity;
ImageView productimage;
TextView quantitynumber,sofaname,sofaprice,sofadesc,totalamount;
Button addtocart;
int quantity;
int totalprice=0;
public Uri mcurrentcarturi;
boolean hasallrequiredvalues = false;
DBHelper DB;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sofa1);
if (getSupportActionBar() != null)
getSupportActionBar().hide();
sofaname=(TextView)findViewById(R.id.sofaname);
sofaprice=(TextView)findViewById(R.id.sofaprice);
sofadesc=(TextView)findViewById(R.id.sofadesc);
plusquantity = findViewById(R.id.addquantity);
minusquantity = findViewById(R.id.subquantity);
quantitynumber = findViewById(R.id.quantity);
addtocart = (Button) findViewById(R.id.addtocart);
productimage = (ImageView)findViewById(R.id.productimage);
DB = new DBHelper(Sofa1.this);
//product - 1
byte[] bytesImage = DB.getProductImage("SELECT F_Image FROM Furniture WHERE F_Type = 'Sofa';");
if (bytesImage != null)
Bitmap bitmap = convertByteArraytoImage(bytesImage);
productimage.setImageBitmap(bitmap);
String Name = DB.getProductNamePrice("SELECT F_Name FROM Furniture WHERE F_Type = 'Sofa';");
String Price = DB.getProductNamePrice("SELECT F_Price FROM Furniture WHERE F_Type = 'Sofa';");
String Desc = DB.getProductNamePrice("SELECT F_Description FROM Furniture WHERE F_Type = 'Sofa';");
sofaname.setText(Name);
sofaprice.setText(Price);
sofadesc.setText(Desc);
plusquantity.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if(quantity<5)
//sofaprice
int baseprice= Integer.parseInt(sofaprice.getText().toString());
quantity++;
displayquantity();
totalprice = baseprice * quantity;
String setnewprice = (String.valueOf(totalprice));
sofaprice.setText(setnewprice);
);
minusquantity.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
int baseprice=0;
String Price = DB.getProductNamePrice("SELECT F_Price FROM Furniture WHERE F_Type = 'Sofa';");
baseprice = Integer.parseInt(Price);
if(quantity>1)
quantity--;
displayquantity();
totalprice = baseprice * quantity;
String setnewprice = (String.valueOf(totalprice));
sofaprice.setText(setnewprice);
);
addtocart.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Toast.makeText(Sofa1.this, "Product Added to cart", Toast.LENGTH_SHORT).show();
SaveCart();
totalamount = (TextView) findViewById(R.id.total);
);
private void SaveCart()
String name = sofaname.getText().toString();
String price = sofaprice.getText().toString();
String quantity = quantitynumber.getText().toString();
byte[] bytesImage = convertImageViewToByteArray(productimage);
ContentValues values = new ContentValues();
values.put(OrderContract.OrderEntry.COLUMN_NAME,name);
values.put(OrderContract.OrderEntry.COLUMN_PRICE,price);
values.put(OrderContract.OrderEntry.COLUMN_QUANTITY,quantity);
values.put(OrderContract.OrderEntry.COLUMN_IMAGE,bytesImage);
if(mcurrentcarturi == null)
Uri newUri = getContentResolver().insert(OrderContract.OrderEntry.CONTENT_URI, values);
if(newUri == null)
Toast.makeText(this, "Failed to add to cart", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this, "Product added to cart", Toast.LENGTH_SHORT).show();
hasallrequiredvalues = true;
private void displayquantity()
quantitynumber.setText(String.valueOf(quantity));
@Override
public @NotNull Loader<Cursor> onCreateLoader(int id, Bundle args)
String[] projection = OrderContract.OrderEntry._ID,
OrderContract.OrderEntry.COLUMN_NAME,
OrderContract.OrderEntry.COLUMN_PRICE,
OrderContract.OrderEntry.COLUMN_QUANTITY,
OrderContract.OrderEntry.COLUMN_IMAGE;
return new CursorLoader(this, mcurrentcarturi, projection, null, null, null);
@Override
public void onLoadFinished(@NotNull Loader<Cursor> loader, Cursor cursor)
if(cursor==null || cursor.getCount() < 1)
return;
if(cursor.moveToFirst())
int name = cursor.getColumnIndex(OrderContract.OrderEntry.COLUMN_NAME);
int price = cursor.getColumnIndex(OrderContract.OrderEntry.COLUMN_PRICE);
int quantity = cursor.getColumnIndex(OrderContract.OrderEntry.COLUMN_QUANTITY);
String nameofsofa = cursor.getString(name);
String priceofsofa = cursor.getString(price);
String quantityofsofa = cursor.getString(quantity);
byte[] bytesImage = cursor.getBlob(cursor.getColumnIndex(OrderContract.OrderEntry.COLUMN_IMAGE));
if (bytesImage != null)
Bitmap bitmap = convertByteArraytoImage(bytesImage);
productimage.setImageBitmap(bitmap);
sofaname.setText(nameofsofa);
sofaprice.setText(priceofsofa);
quantitynumber.setText(quantityofsofa);
@Override
public void onLoaderReset(@NotNull Loader<Cursor> loader)
sofaname.setText("");
sofaprice.setText("");
quantitynumber.setText("");
byte[] bytesImage = DB.getProductImage("SELECT F_Image FROM Furniture WHERE F_Type = 'Sofa';");
if (bytesImage != null)
Bitmap bitmap = convertByteArraytoImage(bytesImage);
productimage.setImageBitmap(bitmap);
private Bitmap convertByteArraytoImage (byte[] bytes)
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
private byte[] convertImageViewToByteArray(ImageView imageView)
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG,80,byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
这是我的日志:
E/androidRuntime: FATAL EXCEPTION: main
Process: com.example.myapp, PID: 12426
java.lang.IllegalArgumentException: Image is Required
at com.example.myapp.OrderProvider.insertCart(OrderProvider.java:96)
at com.example.myapp.OrderProvider.insert(OrderProvider.java:69)
at android.content.ContentProvider$Transport.insert(ContentProvider.java:313)
at android.content.ContentResolver.insert(ContentResolver.java:1845)
at com.example.myapp.Sofa1.SaveCart(Sofa1.java:165)
at com.example.myapp.Sofa1.access$100(Sofa1.java:42)
at com.example.myapp.Sofa1$3.onClick(Sofa1.java:138)
at android.view.View.performClick(View.java:7257)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:992)
at android.view.View.performClickInternal(View.java:7213)
at android.view.View.access$3800(View.java:828)
at android.view.View$PerformClick.run(View.java:27921)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:237)
at android.app.ActivityThread.main(ActivityThread.java:7830)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1040)
I/Process: Sending signal. PID: 12426 SIG: 9
Disconnected from the target VM, address: 'localhost:50639', transport: 'socket'
【问题讨论】:
建议您在数据库中将图像路径或图像 url 存储为 String 而不是 BLOB 并检索它并使用 在 imageview 中显示滑翔 【参考方案1】:嘿,兄弟,抱歉,我认为您必须以错误的方式将数据添加到 SQLite 中
简单用例 - https://www.javatpoint.com/android-sqlite-tutorial
要在 SQLite 数据库中存储图像,您必须使用 URI 您可以轻松地重试和存储而不会出现任何问题或崩溃...不要使用 blob 方法兄弟...我个人不推荐它使用blob
解决方案:
在 uri 中存储为 SQLite 中的字符串,之后如果您想显示图像并将字符串转换为 URI。
Uri 到 String 和 Reverse Machinasim - Converting of Uri to String
【讨论】:
【参考方案2】:在convertImageViewToByteArray
方法的ProductDetails 类中,bitmap.compress(Bitmap.CompressFormat.JPEG,80,byteArrayOutputStream);
行假定转换。但是,如果您查看bitmap.compress,则无法确定压缩,因此应检查返回的值并在压缩不起作用时采取适当的措施。
也许使用:-
private byte[] convertImageViewToByteArray(ImageView imageView)
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
if (!bitmap.compress(Bitmap.CompressFormat.JPEG,80,byteArrayOutputStream) return new byte[];
return byteArrayOutputStream.toByteArray();
然而,是否可以接受存储一个空字节数组需要考虑并可能适当处理。所以这个修复可能会解决这个问题,但可能只是延迟处理图像(如果有)没有被压缩的根本问题。
此外,存储大图像可能是不可能的,很难或效率低下随后检索。任何接近 250kb 的图像都很大。通常建议不要将图像存储在数据库中,而是将图像存储为文件并存储文件的路径。
【讨论】:
以上是关于检索 blob 时 SQLite 数据库中的异常的主要内容,如果未能解决你的问题,请参考以下文章
adodb.recordset 仅从 sqlite3 数据库中检索部分 blob 数据
错误 java.sql.SQLException:从数据库中检索 Blob(图像)时 SQLite JDBC 驱动程序未实现