检索 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,则无法确定压缩,因此应检查返回的值并在压缩不起作用时采取适当的措施。

根据退货 boolean 如果成功压缩到指定流,则为 true。

也许使用:-

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 驱动程序未实现

从 Android sqlite 数据库中检索大 blob

c# sqlite - 从数据库中检索 BLOB 文本

从 SQLite 数据库中检索图像(BLOB 数据类型)

如何读取存储在 sqlite 数据库中的 blob 类型?