这周练习ListView时遇到了一个问题,从数据库中查询出的数据绑定到LIstView上,长按某个item进行删除操作,每次点击item取得的id都不对,调了半天终于找到了原因,关键是自己对自定义的BaseAdapter没有理解深刻。
先说说ListView使用BaseAdapter的优化技巧。
一般当系统提供的Adapter无法满足项目需求时,就需要自己定制一个Adpater,实现getView等方法给每一个item一个样式,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();
于是在我点击item时取得的id应该是通过参数中position变量获取而不是参数中的id变量
先给出开始时的错误代码:
//点击 @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); }
代码片段如下:
@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()方法重新绘制。