Blob Row 太大太适合 Android

Posted

技术标签:

【中文标题】Blob Row 太大太适合 Android【英文标题】:Blob Row too big too fit in Android 【发布时间】:2021-10-30 15:10:31 【问题描述】:

保存到 SQLite 时如何限制图像的大小?当我检索我认为没有从 SQLite 获得大大小的 blob 图像时出现此错误。但是,我尝试在SELECT id,cash_card,hh_number,cc_image FROM CgList limit 500 这样的查询中设置限制 500,但结果是一样的,它使我的应用程序崩溃。

简而言之,有什么办法可以减少图片插入SQLite数据库时的文件大小?

错误

android.database.sqlite.SQLiteBlobTooBigException:行太大而无法容纳 进入 CursorWindow requiredPos=0, totalRows=4

插入数据和blob

 public void insertData(String cash_card, String hh_number,String series_number ,byte[] cc_image,byte[] id_image)
    SQLiteDatabase database = getWritableDatabase();
    String sql = "INSERT INTO CgList VALUES (NULL,?, ?, ?, ?, ?)";
    SQLiteStatement statement = database.compileStatement(sql);
    statement.clearBindings();

    statement.bindString(1, cash_card);
    statement.bindString(2, hh_number);
    statement.bindString(3, series_number);
    statement.bindBlob(4, cc_image);
    statement.bindBlob(5, id_image);
    statement.executeInsert();

获取数据

  Cursor cursor = ScannedDetails.sqLiteHelper.getData("SELECT id,cash_card,hh_number,cc_image FROM CgList");
    list.clear();
    while (cursor.moveToNext())    // the error is here
        int id = cursor.getInt(0);
        String name = cursor.getString(1);
        String price = cursor.getString(2);
        byte[] image = cursor.getBlob(3);

        list.add(new Inventory(name, price, image, id));
    
    adapter.notifyDataSetChanged();

当我点击按钮保存到 SQLite 时

    btnSubmit.setOnClickListener( new View.OnClickListener() 
        @Override
        public void onClick(View v) 
            sqLiteHelper.insertData(
                    edtCashCard.getText().toString().trim(),
                    edtHhnumber.getText().toString().trim(),
                    edtSeriesno.getText().toString().trim(),
                    imageViewToByte(mPreviewCashcard),
                    imageViewToByte(mPreview4PsId)
            );
        
    );

将图像转换为字节

 public static byte[] imageViewToByte(ImageView image) 
   Bitmap bitmap = ((BitmapDrawable)image.getDrawable()).getBitmap();
   ByteArrayOutputStream stream = new ByteArrayOutputStream();
   bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
   byte[] byteArray = stream.toByteArray();
   return byteArray;
 

更新

我认为这是捕获提供更大尺寸的图像时的问题,我需要这个,因为在捕获图像后,我想出于某种目的裁剪图像,但我想将实际捕获而不是裁剪的图像显示给另一个活动

 private void pickCamera() 
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, "NewPic");
    values.put(MediaStore.Images.Media.DESCRIPTION, "Image to Text");
    image_uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);
    Intent cameraIntent = new Intent (MediaStore.ACTION_IMAGE_CAPTURE);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);
    startActivityForResult(cameraIntent, IMAGE_PICK_CAMERA_CODE);

OnActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK)
        if (requestCode == IMAGE_PICK_GALLER_CODE)
            CropImage.activity(data.getData()).setGuidelines(CropImageView.Guidelines.ON).start(this);
        
        if (requestCode == IMAGE_PICK_CAMERA_CODE)

            CropImage.activity(image_uri).setGuidelines(CropImageView.Guidelines.ON).start(this);
        
    
    if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE)
        CropImage.ActivityResult result = CropImage.getActivityResult(data);
        if(resultCode ==RESULT_OK)
            Uri resultUri = result.getUri();
            resultUri.getPath();
            mPreviewIv.setImageURI(resultUri);
            BitmapDrawable bitmapDrawable = (BitmapDrawable)mPreviewIv.getDrawable();
            Bitmap bitmap = bitmapDrawable.getBitmap();
            TextRecognizer recognizer = new TextRecognizer.Builder(getApplicationContext()).build();

            if(!recognizer.isOperational())
                Toast.makeText(this,"Error",Toast.LENGTH_SHORT).show();
            
            else
                Frame frame = new Frame.Builder().setBitmap(bitmap).build();
                SparseArray<TextBlock> items = recognizer.detect(frame);
                StringBuilder sb = new StringBuilder();

                for (int i = 0; i<items.size(); i++)
                    TextBlock myItem = items.valueAt(i);
                    sb.append(myItem.getValue());
                    sb.append("\n");
                
                
                Intent i = new Intent(MainActivity.this, ScannedDetails.class);   
                //camera
                i.putExtra("CashCardImage",image_uri.toString());  //This data pass to another activity
                startActivity(i);
            
        
    

检索到另一个活动

Bundle extras = getIntent().getExtras();
   String resultUri = extras.getString("CashCardImage");
   Uri myUri = Uri.parse(resultUri);
   mPreviewCashCard.setImageURI(myUri);

我在保存到 SQLITE 时尝试的另一个大小并不大,它只是 KIB,我认为问题出在第一个 PickCamera 但这些代码需要裁剪图像

 private void pickCamera() 
   Intent intent = new Intent(ScannedDetails.this, InventoryList.class);
   startActivity(intent);
   

【问题讨论】:

这能回答你的问题吗? SQLiteBlobTooBigException: Row too big to fit into CursorWindow requiredPos=0, totalRows=1 顺便说一句。在 sqlite 中保留这么大的 blob 效率非常低(保存/获取) @ArthurAttout 感谢您的回复,但我不明白那里的答案您能告诉我发生了什么,这是插入数据时的问题吗? @snachmsm 感谢您的回复 有没有限制图片大小的方法? 我尝试了上面的第一个答案,它显示了图像,但问题是,有没有办法在保存到 SQLITE 时限制图像的大小? @Arthur Attout 【参考方案1】:

但是,我尝试在查询中设置限制 500,例如 SELECT id,cash_card,hh_number,cc_image FROM CgList limit 500

LIMIT 限制返回的行数,不限制行的大小。

问题是单行超出了光标使用的缓存/缓冲区 (CursorWindow) 的容量。插入所述行/行时,此限制不适用。

典型的解决方案是不存储图像,而是存储参考,例如文件路径,然后可以从中检索图像(或其他大型项目)。

Here's an example that stores images less than a set size (100k in the example) as a blob and those larger as files in data/data/myimages, which could be another solution.

可以将大图像分解为数据块并存储/检索。 Here's an example of doing that.

【讨论】:

感谢您的回复 我试过了,但我还是不明白,我也是一个学习缓慢的人,我不知道如何将源代码应用到我的代码中,请需要帮助 @ShainnahJane 你的第一步是决定你将如何处理图像的存储,作为 1) 数据块,作为 2) 对文件的引用或 3) 混合存储那些可以存储和其他作为参考。然后检查相关示例并提取/修改方法以适应。 感谢您的回复我打算将带有图像的数据保存到手机中的 SQLite,图像来自我的相机,问题是我应该使用BLOB 保存图像的最佳方法是什么还是只是 imageUri 的路径? @ShainnahJane uri,虽然这很容易受到移动图像的影响。 其实我有两个ImagePreview,保存到SQLITE的时候,两个图片的文件大小是不一样的,一个只是KIB,另一个更大是MiB我觉得没问题在 SQLite 中插入不同之处在于我如何捕获相机,但我不知道为什么它们的文件大小不同【参考方案2】:

不要将图像直接存储在数据库中。相反,将图像保存到文件或网络服务器。然后在数据库中存储图像的文件路径或 URL。

【讨论】:

感谢您的回复,但我打算将数据保存到手机中的 SQLite,然后我想将所有数据与图像同步并通过 API 发送,但现在,我知道问这个问题有点常见但仍然没有解决我如何将图像大小限制为我的 SQLite 的问题,请您帮忙。

以上是关于Blob Row 太大太适合 Android的主要内容,如果未能解决你的问题,请参考以下文章

创建models.py时发现row size太大问题,如何解决

MySQL:错误代码:1118 行大小太大(> 8126)。将某些列更改为 TEXT 或 BLOB

数据库报错 [ERR] 1118 - Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_F

一元微分学的选择中的定理大总结

Codeforces 650 DZip-line

MySQL - Row size too large (> 8126). Changing some columns to TEXT or BLOB