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后添加:
然后在Provider的insert/update/delete方法末尾调用:cursor.setNotificationUri(getContext().getContentResolver(), TodoEntry.CONTENT_URI);
这样数据变化时UI会自动刷新,体验更流畅。getContext().getContentResolver().notifyChange(uri, null);
按照上面的步骤修改后,你的空指针问题应该就能彻底解决了。
内容的提问来源于stack exchange,提问作者sixcookies
相关产品推荐
相关产品推荐

