1

我有一个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为空?是否有一些文档描述了游标和适配器如何适应活动生命周期?

更新

我摆脱了android:onClick我的 XML 文件并在其中手动设置了侦听器SimpleCursorAdapter.bindView。为避免泄漏,我在自定义AbsListView.RecycleListener和活动中删除了侦听器onPause(我使用 检索所有视图reclaimViews(List<View>))。这似乎修复了错误,这是我的解释。

  1. 当我的活动第一次开始时,一个新的视图被夸大了
  2. android:onClick解析属性时,我的活动的实例#1 在视图的构造函数中设置为该特定视图的 OnClickListener
  3. instance#1 离开前台,因此 onPause() 将光标设置为空。请注意,此活动仍然是视图的侦听器,因为视图和活动都没有标记为垃圾回收。这意味着它们在 Android 类的某些缓存中被引用
  4. 我的活动的实例#2 被创建,它的列表视图在某种程度上回收了已经创建的视图。数据显示正确,但此视图仍将旧活动(带有空光标)作为侦听器
  5. 当用户单击我的视图时,将调用 instance#1 处理程序,但它有一个空光标。这会导致 NPE

这个解释很现实,但是我在Android类中没有找到相关代码(里面有缓存AbsListView.RecycleBin,但是ListView本身没有复用)。此外,我从来没有能够重现这个错误,我只是认为我的修复工作是因为在过去的两天里我没有收到任何报告(通常我每天收到几十个)

您是否知道 Android 堆栈中的任何代码可以验证我的假设?

4

2 回答 2

0

我认为您在 Activity 生命周期中的错误点创建光标。ListView 示例onCreate()您拥有的内容放入onResume(). 我不知道它一定有害,但您可能正在重新创建一些不需要的东西。

于 2012-05-10T12:22:33.477 回答
0

你可以试试这个方法。 if (cursor.moveToFirst()) { for (int i = 0; i < cursor.getCount(); i++) { cursor.moveToPosition(i); } }

于 2012-05-07T03:37:24.963 回答