ListViewの使用中に発生した問題
5492 ワード
今週ListViewの練習中に問題が発生し、データベースから検索したデータがLIstViewにバインドされ、あるitemを長押しして削除操作を行い、itemをクリックするたびに取得したidが間違っていたため、半日調整してやっと原因を見つけた.肝心なのは自分がカスタマイズしたBaseAdapterを理解していないことだ.
まずListViewがBaseAdapterを使用する最適化テクニックについてお話しします.
一般的にシステムが提供するAdapterがプロジェクトのニーズを満たすことができない場合、自分でAdpaterをカスタマイズし、getViewなどの方法を実現してitemごとにスタイルを1つずつ与える必要があります.getViewメソッドは、Itemオブジェクトごとに画面に描画されると、「ねえ、boy、私はあなたの前に現れますが、私がどんな顔をしてほしいのか分かりません.getViewメソッドでスタイルを選んでください」というメッセージを送ってくれます.そこでitemの新しいスタイルレイアウトを描きます.しかしitemというやつが私たちに手伝ってもらうたびに、レイアウトオブジェクトを再描画し、明らかにシステムの性能に影響を与えるので、最適化してレイアウトをキャッシュする必要があります.ここで公式に推奨されているのはViewHolderオブジェクトを採用することです.キャッシュから直接取り出しitemに捨てる.
具体的なコードは以下の通りです.
ここにある場所から気づかなかった
このコードidはpostitionの位置に基づいて得られる.
そこでitemをクリックすると取得したidはパラメータのid変数ではなくパラメータのposition変数で取得されるはずです
開始時のエラーコードを先に示します.
正しいコードは次のとおりです.
また、コンテキストメニューでitemのidを取得する場合、MenuItemオブジェクトパラメータが1つしかない場合は、AdapterViewを利用する.AdapterContextMenuInfoオブジェクト取得id
コードクリップは次のとおりです.
まずListViewがBaseAdapterを使用する最適化テクニックについてお話しします.
一般的にシステムが提供するAdapterがプロジェクトのニーズを満たすことができない場合、自分でAdpaterをカスタマイズし、getViewなどの方法を実現してitemごとにスタイルを1つずつ与える必要があります.getViewメソッドは、Itemオブジェクトごとに画面に描画されると、「ねえ、boy、私はあなたの前に現れますが、私がどんな顔をしてほしいのか分かりません.getViewメソッドでスタイルを選んでください」というメッセージを送ってくれます.そこでitemの新しいスタイルレイアウトを描きます.しかしitemというやつが私たちに手伝ってもらうたびに、レイアウトオブジェクトを再描画し、明らかにシステムの性能に影響を与えるので、最適化してレイアウトをキャッシュする必要があります.ここで公式に推奨されているのはViewHolderオブジェクトを採用することです.キャッシュから直接取り出しitemに捨てる.
具体的なコードは以下の通りです.
public class NoteListAdapter extends BaseAdapter {
private List<Note> noteList = null;
private LayoutInflater layoutInflater;
private static final String TAG = NoteListAdapter.class.getSimpleName();
public NoteListAdapter(Context context, List<Note> list) {
this.noteList = list;
layoutInflater = LayoutInflater.from(context);
}
public void setNoteList(List<Note> noteList) {
this.noteList = noteList;
}
// List Item
@Override
public int getCount() {
return noteList.size();
}
// Item
@Override
public Object getItem(int position) {
return noteList.get(position);
}
// Item Id
@Override
public long getItemId(int position) {
return position;
}
@SuppressLint("SimpleDateFormat")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Log.i(TAG, "getView ");
ViewHolder holder;
if (convertView == null) {
convertView = layoutInflater.inflate(
R.layout.note_list, null);
holder = new ViewHolder();
TextView tv = (TextView) convertView
.findViewById(R.id.tv_info_title);
holder.setInfotitle(tv);
TextView tvtime = (TextView) convertView
.findViewById(R.id.tv_info_time);
holder.setInfotime(tvtime);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
if(!TextUtils.isEmpty(noteList.get(position).getTitle().toString().trim())){
long id = noteList.get(position).getId();
String title = noteList.get(position).getTitle();
Date date = noteList.get(position).getCreateDate();
Log.i(TAG, " Adapter Id"+id);
holder.getInfotitle().setText(title);
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
holder.getInfotime().setText(format.format(date));
}
return convertView;
}
private class ViewHolder {
private TextView infotitle;
private TextView infotime;
public TextView getInfotitle() {
return infotitle;
}
public void setInfotitle(TextView infotitle) {
this.infotitle = infotitle;
}
public TextView getInfotime() {
return infotime;
}
public void setInfotime(TextView infotime) {
this.infotime = infotime;
}
}
}
ここにある場所から気づかなかった
long id = noteList.get(position).getId();
このコードidはpostitionの位置に基づいて得られる.
そこでitemをクリックすると取得したidはパラメータのid変数ではなくパラメータのposition変数で取得されるはずです
開始時のエラーコードを先に示します.
//
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(this,NoteAddActivity.class);
// id
intent.putExtra("id", id);
intent.putExtra("edit", true);
startActivity(intent);
}
正しいコードは次のとおりです.
//
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(this,NoteAddActivity.class);
id = noteList.get(position).getId();
intent.putExtra("id", id);
intent.putExtra("edit", true);
startActivity(intent);
}
また、コンテキストメニューでitemのidを取得する場合、MenuItemオブジェクトパラメータが1つしかない場合は、AdapterViewを利用する.AdapterContextMenuInfoオブジェクト取得id
コードクリップは次のとおりです.
@Override
public boolean onContextItemSelected(MenuItem item) {
//
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
// Item ID
final Long MID = noteList.get(info.position).getId();
switch (item.getItemId()) {
//
case ITEM1:
service = DbService.getInstance(this);
AlertDialog.Builder builder = new AlertDialog.Builder(ManagerActivity.this);
builder.setTitle(" ").setIcon(android.R.drawable.ic_dialog_alert).setMessage(" ?")
.setNegativeButton(" ", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
}).setPositiveButton(" ", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Runnable deleteNote = new Runnable() {
@Override
public void run() {
// handler
service.deleteNote(MID);
Toast.makeText(ManagerActivity.this, " ", Toast.LENGTH_SHORT)
.show();
Log.i(TAG, " ID"+MID);
noteList = service.loadAllNote();
ma.setNoteList(noteList);
ma.notifyDataSetChanged();
}
};
myHandler.post(deleteNote);
}
}).create().show();
return true;
最後に注意した点は、adpterのlistデータが変化した場合、新しいlistオブジェクトsetをadpterオブジェクトに渡す必要があり、後にnotifyDataSetChanged()メソッドを加えて再描画することを忘れないでください.