"Make sure Cursor is initialized before accessing data from it" Android
"Make sure Cursor is initialized before accessing data from it" Android
我知道这个问题以前被问过很多次,但在这种情况下是不同的,因为错误仅在尝试将图像保存到数据库时发生,而其他问题不涉及图像。有的话请评论link.
首先,我只发布我认为必要的代码,所以如果我遗漏了某些代码或任何内容,请告诉我。我有一个 note-taking 应用程序,它存储 2 个不同的 EditText 字段作为注释标题和注释 body。那很好用。我尝试添加功能以从 SQLite 数据库添加、存储和检索图像。这是我的 EditNoteActivity class 中的代码,它在用户完成编辑笔记并按下后退按钮转到 MainActivity class.
后的 "store" 操作期间运行
private void updateNote(String noteText, String titleText) {
Log.d("Img", "updateNote");
ContentValues values = new ContentValues();
ImageView img = (ImageView) findViewById(R.id.imageView);
byte[] data;
if (img.getDrawable() != null) {
Log.d("Img", "updateNote ----- image here");
Bitmap bitmap = ((BitmapDrawable)img.getDrawable()).getBitmap();
// data = getBitmapAsByteArray(bitmap);
data = DbBitmapUtility.getBytes(bitmap);
} else {
Log.d("Img", "updateNote ----- image not here");
data = null;
}
values.put(DBOpenHelper.NOTE_IMAGE, data);
values.put(DBOpenHelper.NOTE_BODY, noteText);
values.put(DBOpenHelper.NOTE_TITLE, titleText);
// reusing noteFilter value to make sure you're only updating 1 selected row
getContentResolver().update(NoteProvider.CONTENT_URI, values, noteFilter, null);
Toast.makeText(this, R.string.note_updated, Toast.LENGTH_SHORT).show();
setResult(RESULT_OK); // send message to MainActivity saying something has changed, update content in list
}
如果我不向 ImageView 添加图像,那么我可以毫无问题地保存笔记。但是如果我添加图像然后尝试返回 MainActivity,程序会在以下行崩溃:
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
cursorAdapter.swapCursor(data); // crashes here
}
它也在 class 声明中崩溃:
public class MainActivity extends AppCompatActivity
因为我经常使用 Log.d,它确实在 logcat 中说了以下内容:
updateNote
updateNote ----- image here
如果您遵循 updateNote
方法中的代码,它应该是这样。这是 DbBitmapUtility class 中的 getBytes
方法,我用它来获取字节数组以将图像存储为 BLOB:
// convert from bitmap to byte array
public static byte[] getBytes(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
return stream.toByteArray();
}
最后是我的数据库设置:
public static final String TABLE_NOTES = "notes";
public static final String NOTE_ID = "_id";
public static final String NOTE_TITLE = "noteTitle";
public static final String NOTE_BODY = "noteBody";
public static final String NOTE_IMAGE = "noteImage";
public static final String NOTE_CREATED = "noteCreated";
public static final String[] ALL_COLUMNS =
{NOTE_ID, NOTE_TITLE, NOTE_BODY, NOTE_IMAGE, NOTE_CREATED};
// SQL to create table
private static final String TABLE_CREATE =
"CREATE TABLE " + TABLE_NOTES + " (" +
NOTE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
NOTE_TITLE + " TEXT, " +
NOTE_BODY + " TEXT, " +
NOTE_IMAGE + " BLOB, " +
NOTE_CREATED + " TEXT default CURRENT_TIMESTAMP" +
")";
错误如下:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.beauty.comp_eng.mynote, PID: 16435
java.lang.IllegalStateException: Couldn't read row 0, col 0 from
CursorWindow. Make sure the Cursor is initialized correctly before
accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:511)
at
android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
at android.database.CursorWrapper.getLong(CursorWrapper.java:127)
at android.widget.CursorAdapter.getItemId(CursorAdapter.java:259)
at android.widget.AdapterView.rememberSyncState(AdapterView.java:1243)
at
android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:830)
at
android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6470)
at
android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
at
android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
at android.widget.CursorAdapter.swapCursor(CursorAdapter.java:381)
at
com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:200)
at
com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:25)
at
android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:479)
at
android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:447)
at android.support.v4.content.Loader.deliverResult(Loader.java:126)
at
android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:105)
at
android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:37)
at
android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:249)
at
android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:77)
at
android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:466)
at
android.support.v4.content.ModernAsyncTask.access0(ModernAsyncTask.java:48)
at
android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:483)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5525)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
我以为我正确地存储了图像,因为我发现他们在许多其他 Whosebug 答案中都是这样做的,但它不起作用。我注意到它说
Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
如果数据库中已有无图片的普通笔记,为什么没有返回记录?
Android sqlite 游标有一个固定大小的内部缓冲区,称为 CursorWindow
,在大多数配置下为 2MB。尝试在游标行中移动更多数据将不起作用。
不要在 Android sqlite 数据库中存储图像数据或任何其他大数据。相反,将图像存储到文件系统并将文件路径存储在数据库中。
我知道这个问题以前被问过很多次,但在这种情况下是不同的,因为错误仅在尝试将图像保存到数据库时发生,而其他问题不涉及图像。有的话请评论link.
首先,我只发布我认为必要的代码,所以如果我遗漏了某些代码或任何内容,请告诉我。我有一个 note-taking 应用程序,它存储 2 个不同的 EditText 字段作为注释标题和注释 body。那很好用。我尝试添加功能以从 SQLite 数据库添加、存储和检索图像。这是我的 EditNoteActivity class 中的代码,它在用户完成编辑笔记并按下后退按钮转到 MainActivity class.
后的 "store" 操作期间运行private void updateNote(String noteText, String titleText) {
Log.d("Img", "updateNote");
ContentValues values = new ContentValues();
ImageView img = (ImageView) findViewById(R.id.imageView);
byte[] data;
if (img.getDrawable() != null) {
Log.d("Img", "updateNote ----- image here");
Bitmap bitmap = ((BitmapDrawable)img.getDrawable()).getBitmap();
// data = getBitmapAsByteArray(bitmap);
data = DbBitmapUtility.getBytes(bitmap);
} else {
Log.d("Img", "updateNote ----- image not here");
data = null;
}
values.put(DBOpenHelper.NOTE_IMAGE, data);
values.put(DBOpenHelper.NOTE_BODY, noteText);
values.put(DBOpenHelper.NOTE_TITLE, titleText);
// reusing noteFilter value to make sure you're only updating 1 selected row
getContentResolver().update(NoteProvider.CONTENT_URI, values, noteFilter, null);
Toast.makeText(this, R.string.note_updated, Toast.LENGTH_SHORT).show();
setResult(RESULT_OK); // send message to MainActivity saying something has changed, update content in list
}
如果我不向 ImageView 添加图像,那么我可以毫无问题地保存笔记。但是如果我添加图像然后尝试返回 MainActivity,程序会在以下行崩溃:
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
cursorAdapter.swapCursor(data); // crashes here
}
它也在 class 声明中崩溃:
public class MainActivity extends AppCompatActivity
因为我经常使用 Log.d,它确实在 logcat 中说了以下内容:
updateNote updateNote ----- image here
如果您遵循 updateNote
方法中的代码,它应该是这样。这是 DbBitmapUtility class 中的 getBytes
方法,我用它来获取字节数组以将图像存储为 BLOB:
// convert from bitmap to byte array
public static byte[] getBytes(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
return stream.toByteArray();
}
最后是我的数据库设置:
public static final String TABLE_NOTES = "notes";
public static final String NOTE_ID = "_id";
public static final String NOTE_TITLE = "noteTitle";
public static final String NOTE_BODY = "noteBody";
public static final String NOTE_IMAGE = "noteImage";
public static final String NOTE_CREATED = "noteCreated";
public static final String[] ALL_COLUMNS =
{NOTE_ID, NOTE_TITLE, NOTE_BODY, NOTE_IMAGE, NOTE_CREATED};
// SQL to create table
private static final String TABLE_CREATE =
"CREATE TABLE " + TABLE_NOTES + " (" +
NOTE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
NOTE_TITLE + " TEXT, " +
NOTE_BODY + " TEXT, " +
NOTE_IMAGE + " BLOB, " +
NOTE_CREATED + " TEXT default CURRENT_TIMESTAMP" +
")";
错误如下:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.beauty.comp_eng.mynote, PID: 16435 java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetLong(Native Method) at android.database.CursorWindow.getLong(CursorWindow.java:511) at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) at android.database.CursorWrapper.getLong(CursorWrapper.java:127) at android.widget.CursorAdapter.getItemId(CursorAdapter.java:259) at android.widget.AdapterView.rememberSyncState(AdapterView.java:1243) at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:830) at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6470) at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37) at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50) at android.widget.CursorAdapter.swapCursor(CursorAdapter.java:381) at com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:200) at com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:25) at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:479) at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:447) at android.support.v4.content.Loader.deliverResult(Loader.java:126) at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:105) at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:37) at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:249) at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:77) at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:466) at android.support.v4.content.ModernAsyncTask.access0(ModernAsyncTask.java:48) at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:483) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5525) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
我以为我正确地存储了图像,因为我发现他们在许多其他 Whosebug 答案中都是这样做的,但它不起作用。我注意到它说
Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
如果数据库中已有无图片的普通笔记,为什么没有返回记录?
Android sqlite 游标有一个固定大小的内部缓冲区,称为 CursorWindow
,在大多数配置下为 2MB。尝试在游标行中移动更多数据将不起作用。
不要在 Android sqlite 数据库中存储图像数据或任何其他大数据。相反,将图像存储到文件系统并将文件路径存储在数据库中。