【问题标题】:"Make sure Cursor is initialized before accessing data from it" Android“确保在从光标访问数据之前初始化光标”Android
【发布时间】:2017-01-01 08:42:45
【问题描述】:

我知道这个问题之前已经被问过很多次,但在这种情况下它是不同的,因为该错误仅在尝试将图像保存到数据库时发生,而其他问题没有处理图像。如果有,请在链接中发表评论。

首先我只发布我认为必要的代码,所以如果我错过了一些代码或任何东西,请告诉我。我有一个笔记应用程序,它将 2 个不同的 EditText 字段存储为笔记标题和笔记正文。这很好用。我尝试添加功能以从 SQLite 数据库添加、存储和检索图像。这是我的 EditNoteActivity 类中的代码,它在用户完成编辑笔记并按下后退按钮转到 MainActivity 类后的“存储”操作期间运行。

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
}

它也会在类声明中崩溃:

public class MainActivity extends AppCompatActivity

由于我经常使用 Log.d,它在 logcat 中确实说明了以下内容:

更新说明 updateNote ----- 图片在这里

如果您遵循updateNote 方法中的代码,它应该会这样。这是 DbBitmapUtility 类中的 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: 致命异常: main 进程:com.beauty.comp_eng.mynote,PID:16435 java.lang.IllegalStateException:无法读取第 0 行,第 0 列 光标窗口。确保光标在之前正确初始化 从中访问数据。 在 android.database.CursorWindow.nativeGetLong(本机方法) 在 android.database.CursorWindow.getLong(CursorWindow.java:511) 在 android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) 在 android.database.CursorWrapper.getLong(CursorWrapper.java:127) 在 android.widget.CursorAdapter.getItemId(CursorAdapter.java:259) 在 android.widget.AdapterView.rememberSyncState(AdapterView.java:1243) 在 android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:830) 在 android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6470) 在 android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37) 在 android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50) 在 android.widget.CursorAdapter.swapCursor(CursorAdapter.java:381) 在 com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:200) 在 com.beauty.comp_eng.mynote.MainActivity.onLoadFinished(MainActivity.java:25) 在 android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:479) 在 android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:447) 在 android.support.v4.content.Loader.deliverResult(Loader.java:126) 在 android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:105) 在 android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:37) 在 android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:249) 在 android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:77) 在 android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:466) 在 android.support.v4.content.ModernAsyncTask.access$400(ModernAsyncTask.java:48) 在 android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:483) 在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:148) 在 android.app.ActivityThread.main(ActivityThread.java:5525) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)

我以为我正确存储了图像,因为我发现他们在许多其他 stackoverflow 答案中都是这样做的,但它不起作用。我注意到它说

无法从 CursorWindow 读取第 0 行第 0 列。确保 Cursor 在从中访问数据之前已正确初始化。

如果数据库中已经有没有图像的普通笔记,为什么没有返回记录?

【问题讨论】:

    标签: android sqlite blob


    【解决方案1】:

    Android sqlite 游标有一个名为CursorWindow 的固定大小的内部缓冲区,在大多数配置中为 2MB。尝试在游标行中移动更多数据是行不通的。

    不要在 Android sqlite 数据库中存储图像数据或任何其他大型数据。相反,将图像存储到文件系统并将文件路径存储在数据库中。

    【讨论】:

    • 我从来不知道,谢谢你的回答。我暂时投了赞成票,今天下班回家试试看,我会接受你的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多