英文:
Why is getBlob() retrieving Integer data from my Blob column in my database?
问题
I've translated the provided content for you. Please note that the code parts are preserved as-is, without translation.
我试图将来自我的SQLite数据库的数据显示在循环视图中。我试图显示的数据是图像和文本。对于数据库中的图像,我将图像资源转换为位图,然后转换为字节,并将字节存储在Blob列中。然而,当我尝试使用`getBlob()`从列中检索字节时,我收到了异常。
异常是`android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): INTEGER data in nativeGetBlob`。我知道这个异常是发生在`getBlob()`从Blob列中检索整数数据。但我不明白为什么`getBlob()`会检索整数数据,因为我是将字节放入Blob列中的。
我尝试过使用`getInt()`,但这不起作用,因为我的适配器使用`BitmapFactory.decodeByteArray()`,它期望一个字节参数来将列中的字节转换为位图。
***SQLite数据库:***
(代码部分)
***Recycler View类***
(代码部分)
***Recycler view适配器:***
(代码部分)
***异常:***
(异常堆栈跟踪)
请注意,我已按照您的要求翻译了内容,保留了代码部分的原始内容。如果您需要进一步的帮助,请随时提问。
英文:
I am trying to display the data from my SQLite database to the recycler views. The data I am trying to display is an image & text. For the images in my database, I converted the image resources into bitmaps then into bytes & stored the bytes in my Blob column. However when I am trying to retrieve the bytes from the column using the getBlob()
I receive an exception.
The exception is android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): INTEGER data in nativeGetBlob
. I know that this exception is occurring because the getBlob()
retrieves Integer data from my Blob column. But I don't understand I put bytes into my Blob column, so why is getBlob()
retrieving Integer data?
I have tried using the getInt()
but that doesn't work because my adapter uses BitmapFactory.decodeByteArray()
which expects a byte parameter to convert the bytes from my column into a bitmap.
SQLite database:
package com.myapps.myapplication;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "starbuzz";
private static final int DB_VERSION = 6;
private Context context;
private ArrayList <Bitmap> bitmapArray;
private byte [] byteArray;
public MyDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE GROCERY_ITEMS (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + "NAME TEXT, " + "IMAGE_RESOURCE_ID BLOB);");
upgradeDatabase(db);
}
public void upgradeDatabase (SQLiteDatabase db) {
convertToBitmap();
byteArray = convertToByte();
addItems(db);
}
public void convertToBitmap () {
Bitmap faan = BitmapFactory.decodeResource(context.getResources(), R.drawable.faan);
Bitmap milk = BitmapFactory.decodeResource (context.getResources(), R.drawable.milk);
Bitmap egg = BitmapFactory.decodeResource (context.getResources(), R.drawable.egg);
Bitmap toilet_tissue = BitmapFactory.decodeResource (context.getResources(), R.drawable.toilet_tissue);
Bitmap kitchen_tissue = BitmapFactory.decodeResource (context.getResources(), R.drawable.kitchen_tissue);
Bitmap bread = BitmapFactory.decodeResource (context.getResources(), R.drawable.bread);
Bitmap potatoe = BitmapFactory.decodeResource (context.getResources(), R.drawable.potatoe);
Bitmap onion = BitmapFactory.decodeResource (context.getResources(), R.drawable.onion);
Bitmap flour = BitmapFactory.decodeResource (context.getResources(), R.drawable.flour);
Bitmap tomatoe = BitmapFactory.decodeResource (context.getResources(), R.drawable.tomatoe);
Bitmap corriandor = BitmapFactory.decodeResource (context.getResources(), R.drawable.corriandor);
bitmapArray = new ArrayList <Bitmap> ();
bitmapArray.add(faan);
bitmapArray.add (milk);
bitmapArray.add (egg);
bitmapArray.add (toilet_tissue);
bitmapArray.add (kitchen_tissue);
bitmapArray.add (bread);
bitmapArray.add (potatoe);
bitmapArray.add (onion);
bitmapArray.add (flour);
bitmapArray.add (tomatoe);
bitmapArray.add (corriandor);
}
public byte [] convertToByte () {
ByteArrayOutputStream stream = new ByteArrayOutputStream ();
for (Bitmap bitmap : bitmapArray) {
bitmap.compress (Bitmap.CompressFormat.PNG, 0, stream);
}
return stream.toByteArray();
}
public static Bitmap getImages (byte [] image) {
return BitmapFactory.decodeByteArray(image, 0, image.length);
}
public void addItems (SQLiteDatabase db) {
byte faan = byteArray [0];
byte milk = byteArray [1];
byte egg = byteArray [2];
byte toilet_tissue = byteArray [3];
byte kitchen_tissue = byteArray [4];
byte bread = byteArray [5];
byte potatoe = byteArray [6];
byte onion = byteArray [7];
byte flour = byteArray [8];
byte tomatoe = byteArray [9];
byte corriandor = byteArray [10];
insertItems (db, "Faan", faan);
insertItems (db, "Milk", milk);
insertItems (db, "Egg", egg);
insertItems (db, "Toilet Tissue", toilet_tissue);
insertItems (db, "Kitchen Tissue", kitchen_tissue);
insertItems (db, "Bread", bread);
insertItems (db, "Potatoe", potatoe);
insertItems (db, "Onion", onion);
insertItems (db, "Flour", flour);
insertItems (db, "Tomatoe", tomatoe);
insertItems (db, "Corriandor", corriandor);
}
public void insertItems (SQLiteDatabase db, String name, byte image) {
ContentValues contentValues = new ContentValues();
contentValues.put ("NAME", name);
contentValues.put ("IMAGE_RESOURCE_ID", image);
db.insert ("GROCERY_ITEMS", null, contentValues);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("CREATE TABLE GROCERY_ITEMS (" + "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + "NAME TEXT, " + "IMAGE_RESOURCE_ID BLOB);");
upgradeDatabase(db);
}
}
Recycler View class
package com.myapps.myapplication;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class grocery_item extends AppCompatActivity {
SQLiteDatabase db;
Cursor cursor;
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_grocery);
accessDataBase();
RecyclerView groceryRecycler = (RecyclerView) findViewById(R.id.grocery_recycler_view);
captionedImagesAdapter adapter = new captionedImagesAdapter (this, cursor);
GridLayoutManager layoutManager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
groceryRecycler.setLayoutManager(layoutManager);
groceryRecycler.setAdapter (adapter);
}
public void accessDataBase () {
MyDatabaseHelper databaseHelper = new MyDatabaseHelper(this);
try {
db = databaseHelper.getReadableDatabase();
cursor = db.query ("GROCERY_ITEMS", new String[] {"NAME", "IMAGE_RESOURCE_ID"}, null, null, null, null, null);
} catch (SQLiteException e) {
e.printStackTrace();
}
}
}
Recycler view adapter:
package com.myapps.myapplication;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.cardview.widget.CardView;
public class captionedImagesAdapter extends RecyclerView.Adapter <captionedImagesAdapter.ViewHolder> {
private Context context;
private Cursor cursor;
public captionedImagesAdapter (Context context, Cursor cursor) {
this.context = context;
this.cursor = cursor;
}
public captionedImagesAdapter.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
CardView cv = (CardView) inflater.inflate(R.layout.card_view, parent, false);
return new ViewHolder (cv);
}
public void onBindViewHolder(ViewHolder holder, int position) {
if (!cursor.moveToPosition(position)) {
return;
}
String info_text = cursor.getString (0);
byte [] info_image = cursor.getBlob(1);
Bitmap bitmap = MyDatabaseHelper.getImages(info_image);
holder.textView.setText(info_text);
holder.imageView.setImageBitmap(bitmap);
}
public int getItemCount() {
return cursor.getCount();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private TextView textView;
public ViewHolder(CardView view) {
super(view);
imageView = view.findViewById(R.id.info_image);
textView = view.findViewById(R.id.info_text);
}
}
}
Exception:
android.database.sqlite.SQLiteException: unknown error (code 0 SQLITE_OK): INTEGER data in nativeGetBlob
at android.database.CursorWindow.nativeGetBlob(Native Method)
at android.database.CursorWindow.getBlob(CursorWindow.java:434)
at android.database.AbstractWindowedCursor.getBlob(AbstractWindowedCursor.java:47)
at com.myapps.myapplication.captionedImagesAdapter.onBindViewHolder(captionedImagesAdapter.java:43)
at com.myapps.myapplication.captionedImagesAdapter.onBindViewHolder(captionedImagesAdapter.java:14)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7178)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7258)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:6125)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6391)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6231)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6227)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
at androidx.recyclerview.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:572)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668)
at androidx.recyclerview.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4230)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3941)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4499)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:786)
at android.view.View.layout(View.java:22085)
at android.view.ViewGroup.layout(ViewGroup.java:6290)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3333)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2810)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1930)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7988)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1154)
at android.view.Choreographer.doCallbacks(Choreographer.java:977)
at android.view.Choreographer.doFrame(Choreographer.java:893)
at android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:1082)
2020-08-12 13:34:17.755 14399-14399/com.myapps.myapplication E/AndroidRuntime: at
android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
答案1
得分: 1
- 你将列名命名为
IMAGE_RESOURCE_ID
,这表明你在其中存储某种标识号码,但它的类型为BLOB
,这表明内容实际上是图像数据本身。这种混淆本身并不是问题,但表明代码没有明确的方向。 - 你将所有图像存储到单个流中,没有办法提取出单独的图像。如果你想要将实际数据存储在数据库中,那么每个位图应该被编码为单独的
byte[]
。 - 你获取结果的前11个字节的超大
byte[]
,并仅将它们存储在数据库中(也分别存储在11个不同的行中)。这些字节可能只是第一个图像头部的开头,本身没有有用的含义。
我的建议:如果你想要存储实际数据,将 convertToBytes
方法更改为接受 Bitmap
参数,并对每个要存储在数据库中的位图调用它一次。
英文:
Where to begin?
- you name the column
IMAGE_RESOURCE_ID
which indicates that you store some kind of identifying number in it, but it's of typeBLOB
which indicates that the content is actually the image data itself. That confusion is not in itself a problem, but indicates that the code hasn't been written with a clear direction in mind. - You store all images into a single stream with no way to pick out the separate images. If you wanted to store the actual data in a database, then each bitmap should be encoded into a separate
byte[]
. - You take the first 11 bytes of the resulting mega-
byte[]
and store only those in the database (in 11 different rows as well). Those bytes are probably just the beginning of the header of the first image and have no useful meaning on their own.
My suggestion: if you want to store the actual data, change the convertToBytes
method to take a Bitmap
argument and call it once for each Bitmap you want to store in the database.
答案2
得分: 0
似乎您查询中的第二列并非您所认为的二进制大对象 (blob);您正在使用 .getBlob(1)
访问它,这意味着:获取第二列的值并将其作为二进制大对象返回给我,但错误似乎表明:不行,它不是二进制大对象,而是整数。
您没有粘贴出您创建 AbstractWindowedCursor 对象的代码;它是传递到 captionedImagesAdapter
类构造函数的游标。这背后的查询是什么?我敢打赌它是 SELECT foo, bar, baz FROM something
,其中 bar
实际上不是二进制大对象值。例如,如果您执行了 SELECT * FROM GROCERY_ITEMS
,那么第一列(例如 .getInt(0)
)是 id 列,第二列是名称(文本),第三列是二进制大对象。如果您尝试在它上运行 .getBlob(1)
,则会出现类似这样的错误,因为 1
是错误的数字。
英文:
It sounds like the second column in your query isn't the blob you thought it was; you're accessing it with .getBlob(1), which means: Take the value of the second column and give it to me as a blob, and the error seems to indicate: .. no can do, it's not a blob, it's an integer.
You haven't pasted where you make your AbstractWindowedCursor object; it is the cursor that is passed into the constructor of your captionedImagesAdapter
class. What query is behind this? I bet it's SELECT foo, bar, baz FROM something
, where bar
is not, actually, a blob value. For example, if you did SELECT * FROM GROCERY_ITEMS
, then the first column (.getInt(0)
for example) is the id column, the second is the name (text), and the third is the blob. You'd end up getting an error similar to this one if you attempted to run .getBlob(1)
on that, because 1
is the wrong number.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论