使用ListView时遇到的问题

这周练习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();

这一句代码id是根据postition的位置来得到的。

于是在我点击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);
	}

另外当在上下文菜单获取item的id时只有一个MenuItem对象参数,这时候应该借助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()方法重新绘制。


你可能感兴趣的:(ListView,viewholder)