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);
  }

}

アクティビティのライフサイクル中にリソースを割り当て/解放するために、データベースとアダプターをアクティビティのインスタンス フィールドに保存します。新しいデータベースを作成してonResume閉じますonPause。残念ながら、ユーザーから、上記の疑似コードで概説した行で NPE がスローされるという報告を多数受け取りましたが、それを再現することはできません。

のようですcursorが、クリックイベントへのコールバックであるため、 の後にのみnullメソッドを呼び出すことができる場合、これがどのように可能になるのだろうか(私は を介し​​て XML レイアウトでこれを設定します) 。onClickRowDumpOrderonResumeandroid:onClick

私は何か間違ったことをしていますか?cursorが null になる原因となる API の誤用は何ですか? カーソルとアダプターがアクティビティのライフサイクルにどのように適合するかを説明するドキュメントはありますか?

アップデート

XML ファイルをandroid:onClick削除し、手動でリスナーを内部に設定しましたSimpleCursorAdapter.bindView。リークを避けるために、カスタムAbsListView.RecycleListenerとアクティビティのいずれかでリスナーを削除しonPauseます (すべてのビューを で取得しますreclaimViews(List<View>))。これでバグが修正されたようです。ここに私の説明があります。

  1. アクティビティが最初に開始されたときに新しいビューが膨らむ
  2. android:onClick私のアクティビティのインスタンス#1は、属性を解析するときに、ビューのコンストラクターでその特定のビューのOnClickListenerとして設定されます
  3. instance#1 はフォアグラウンドを離れるため、onPause() はカーソルを null に設定します。ビューもアクティビティもガベージ コレクションの対象としてマークされていないため、このアクティビティは引き続きビューのリスナーであることに注意してください。これは、Android クラスの一部のキャッシュで参照されていることを意味します。
  4. 私のアクティビティのインスタンス#2が作成され、そのリストビューはすでに作成されたビューをいくらかリサイクルします。データは正しく表示されますが、このビューにはリスナーとして古いアクティビティ (null カーソルを含む) が残っています。
  5. ユーザーがビューをクリックすると、instance#1 ハンドラーが呼び出されますが、null カーソルがあります。これにより、NPE が発生します。

この説明は現実的ですが、Android クラスに関連するコードは見つかりませんでした ( にはキャッシュがありますAbsListView.RecycleBinが、ListView 自体は再利用されていません)。さらに、私はこのバグを再現することができませんでした。過去 2 日間、レポートを受け取っていないため (通常は 1 日に数十件のレポートを受け取ります)、私の修正が機能しているとしか思えません。

私の仮定を検証できる Android スタック内のコードを知っていますか?

4

2 に答える 2

0

アクティビティのライフサイクルの間違った時点でカーソルを作成していると思います。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 に答える