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 レイアウトでこれを設定します) 。onClickRowDumpOrder
onResume
android:onClick
私は何か間違ったことをしていますか?cursor
が null になる原因となる API の誤用は何ですか? カーソルとアダプターがアクティビティのライフサイクルにどのように適合するかを説明するドキュメントはありますか?
アップデート
XML ファイルをandroid:onClick
削除し、手動でリスナーを内部に設定しましたSimpleCursorAdapter.bindView
。リークを避けるために、カスタムAbsListView.RecycleListener
とアクティビティのいずれかでリスナーを削除しonPause
ます (すべてのビューを で取得しますreclaimViews(List<View>)
)。これでバグが修正されたようです。ここに私の説明があります。
- アクティビティが最初に開始されたときに新しいビューが膨らむ
android:onClick
私のアクティビティのインスタンス#1は、属性を解析するときに、ビューのコンストラクターでその特定のビューのOnClickListenerとして設定されます- instance#1 はフォアグラウンドを離れるため、onPause() はカーソルを null に設定します。ビューもアクティビティもガベージ コレクションの対象としてマークされていないため、このアクティビティは引き続きビューのリスナーであることに注意してください。これは、Android クラスの一部のキャッシュで参照されていることを意味します。
- 私のアクティビティのインスタンス#2が作成され、そのリストビューはすでに作成されたビューをいくらかリサイクルします。データは正しく表示されますが、このビューにはリスナーとして古いアクティビティ (null カーソルを含む) が残っています。
- ユーザーがビューをクリックすると、instance#1 ハンドラーが呼び出されますが、null カーソルがあります。これにより、NPE が発生します。
この説明は現実的ですが、Android クラスに関連するコードは見つかりませんでした ( にはキャッシュがありますAbsListView.RecycleBin
が、ListView 自体は再利用されていません)。さらに、私はこのバグを再現することができませんでした。過去 2 日間、レポートを受け取っていないため (通常は 1 日に数十件のレポートを受け取ります)、私の修正が機能しているとしか思えません。
私の仮定を検証できる Android スタック内のコードを知っていますか?