You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用SQLite+ContentProvider Cursor空指针异常求助

排查解决Cursor空指针异常的步骤

首先咱们直接定位核心问题:你碰到的NullPointerException是因为cursor对象为null时调用了cursor.close(),而cursor为null的根源是ContentResolver无法找到匹配的ContentProvider,导致query()方法返回null。下面一步步拆解问题和解决方案:

1. 最致命的错误:Content Authority不匹配

看你的代码细节:

  • 在TodoContract.java中,CONTENT_AUTHORITY设置的是:
    public static final String CONTENT_AUTHORITY = "com.example.android.todos";
    
  • 但在AndroidManifest.xml里,Provider的authorities属性写的是:
    <provider android:name=".database.TodoProvider" android:authorities="com.example.android.memo" android:exported="false" />
    

这两个值必须完全一致!ContentResolver是通过CONTENT_AUTHORITY来定位对应的Provider的,两者不匹配的话,系统根本找不到你的Provider,query()自然返回null。

解决方法:把Manifest里的authorities改成和CONTENT_AUTHORITY一致:

<provider 
    android:name=".database.TodoProvider" 
    android:authorities="com.example.android.todos" 
    android:exported="false" />

2. 必须添加Cursor空值判断

就算修复了Authority的问题,也不能保证query一定返回非null的Cursor(比如数据库操作出错、权限不足等情况),所以在使用Cursor之前一定要加空值判断,避免空指针。

修改displayDatabaseInfo方法:

public void displayDatabaseInfo(TextView displayView) {
    String[] projection = { TodoEntry._ID, TodoEntry.COLUMN_TODO_NAME};
    Cursor cursor = getContext().getContentResolver().query(TodoEntry.CONTENT_URI, projection, null, null, null);
    
    // 先判断cursor是否为null,避免后续操作崩溃
    if (cursor == null) {
        displayView.setText("Failed to retrieve data from database.");
        return;
    }

    try {
        displayView.setText("There are " + cursor.getCount() + " tasks.\n\n");
        int idColumnIndex = cursor.getColumnIndex(TodoEntry._ID);
        int nameColumnIndex = cursor.getColumnIndex(TodoEntry.COLUMN_TODO_NAME);
        while (cursor.moveToNext()) {
            int currentID = cursor.getInt(idColumnIndex);
            String currentName = cursor.getString(nameColumnIndex);
            displayView.append(("\n" + currentID + " - " + currentName));
        }
    } finally {
        // 这里cursor已经经过null判断,不会触发空指针
        cursor.close();
    }
}

3. 额外的优化建议

  • 你在InboxFragment中实例化了TodoDBHelper,但使用ContentProvider的场景下,数据库的操作应该完全由Provider负责,Fragment里不需要自己持有DBHelper实例,建议移除mDBHelper = new TodoDBHelper(getContext());这行代码。
  • 可以给Cursor设置ContentObserver,实现数据变化时自动更新UI,不用在onStart()里手动调用displayDatabaseInfo:
    在query获取cursor后添加:
    cursor.setNotificationUri(getContext().getContentResolver(), TodoEntry.CONTENT_URI);
    
    然后在Provider的insert/update/delete方法末尾调用:
    getContext().getContentResolver().notifyChange(uri, null);
    
    这样数据变化时UI会自动刷新,体验更流畅。

按照上面的步骤修改后,你的空指针问题应该就能彻底解决了。

内容的提问来源于stack exchange,提问作者sixcookies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:36:19