【发布时间】:2012-05-07 00:09:07
【问题描述】:
我有一个ListView,它可以调整来自游标的数据。记录的光标位置通过View.setTag() 存储,因此可以在响应用户事件时检索它。
public class OrderActivity extends Activity {
private ListView list;
private CursorAdapter adapter;
private SQLiteDatabase database;
public void onResume() {
database = new Database(this).getWriteableDatabase();
// query the db and store the position of the cursor
// as the tag while binding the view in the overridden
// CursorAdapter.bindView()
adapter = new SimpleCursorAdapter( /* code here */ );
list.setAdapter(adapter);
}
public void onPause() {
adapter.changeCursor(null);
database.close();
}
private void onClickRowDumpOrder(View row) {
int newPosition = (Integer) row.getTag();
Cursor cursor = adapter.getCursor();
int originalPosition = cursor.getPosition(); // Throws NPE
cursor.moveToPosition(newPosition);
Log.v("tag", "Description: " + cursor.getString(0));
// restore the cursor
cursor.moveToPosition(originalPosition);
}
}
我将数据库和适配器存储在我的 Activity 的实例字段中以在 Activity 生命周期内分配/释放资源:我创建一个新数据库 onResume 并关闭它 onPause。不幸的是,我从我的用户那里收到很多报告,说在上面的伪代码中概述的行中抛出了 NPE,但我无法重现它。
似乎cursor 是null,但我想知道如果方法onClickRowDumpOrder 只能在onResume 之后调用,这怎么可能,因为它是点击事件的回调(我在XML 布局通过android:onClick)
我做错了吗?哪些 API 误用导致 cursor 为空?是否有一些文档描述了游标和适配器如何适应活动生命周期?
更新
我在我的 XML 文件中删除了 android:onClick,并在 SimpleCursorAdapter.bindView 中手动设置了侦听器。为了避免泄漏,我在我的自定义AbsListView.RecycleListener 和我的活动的onPause 中删除了侦听器(我使用reclaimViews(List<View>) 检索所有视图)。这似乎修复了错误,这是我的解释。
- 当我的活动第一次开始时,一个新的视图被膨胀
- 在解析
android:onClick属性时,我的活动的实例#1 在视图的构造函数中被设置为该特定视图的 OnClickListener - instance#1 离开前台,因此 onPause() 将光标设置为空。请注意,此活动仍然是视图的侦听器,因为视图和活动都没有标记为垃圾回收。这意味着它们在 Android 类的某些缓存中被引用
- 我的活动的实例#2 已创建,其列表视图有点回收已创建的视图。数据显示正确,但此视图仍将旧活动(带有空光标)作为侦听器
- 当用户单击我的视图时,实例#1 处理程序被调用,但它有一个空光标。这会导致 NPE
这个解释很现实,但是我在Android类中没有找到相关代码(AbsListView.RecycleBin中有缓存,但是ListView本身没有复用)。此外,我从来没有能够重现这个错误,我只是认为我的修复工作是因为在过去的两天里我没有收到任何报告(通常我每天收到几十个)
您是否知道 Android 堆栈中的任何代码可以验证我的假设?
【问题讨论】:
-
那么你可以在没有 NPE 的情况下在纵向/横向之间快速旋转手机多次吗?
-
是的,无论如何这与我的应用无关,因为它只允许纵向模式,所以当用户旋转设备时,活动不会被破坏
-
请贴出您用于创建光标的代码
-
光标是在
new SimpleCursorAdapter内创建的,带有标准mSQLiteDatabase.query(...),并且不相关。查看更新 -
为什么这个列表需要一个可写的数据库?
标签: android sqlite android-activity nullpointerexception lifecycle