作为一个Android开发小白,ListView重复问题困惑了好久好久,最终在参考别人的文章后终于搞明白了为什么重复以及怎样解决重复问题.
先看一下Demo的界面的吧.
主界面布局就一个ListView,我就不给出了.
主界面代码:
public class MainActivity extends Activity { private ListView listView ; private List<ListItem> dataList; private MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //无标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initView(); } /** * 初始化视图 */ private void initView(){ listView = (ListView) super.findViewById(R.id.list_view); createTestData(); adapter = new MyAdapter(this, dataList); listView.setAdapter(adapter); adapter.setListView(listView); //点击item事件,也可点击按钮. listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //响应点击事件 adapter.itemClick(position); } }); } /** * 创建测试数据 */ private void createTestData(){ dataList = new ArrayList<ListItem>(); for (int i = 0; i < 100; i++) { ListItem item = new ListItem(); item.setProcess(0); item.setText("这是第" + i + "条."); item.setHidden(false); dataList.add(item); } } }
这里可以看出ListView的item点击事件是adapter调用了itemClic()方法,如下:
<span style="white-space:pre"> </span>/** * 响应ListView的点击事件 * @param position */ public void itemClick(int position){ DLog.d("点击了:" + position ); int process = dataList.get(position).getProcess(); if (process > 0 && process < 100) { Toast.makeText(context, "任务正在进行", Toast.LENGTH_SHORT).show(); } else if (process == 0 || process == 100) { changeData(position); } }
当用户点击item使去改变相应的数据changeData():
/** * 更改数据 * @param position */ public void changeData(final int position){ DLog.d("改变数据" ); new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ListItem tempItem = dataList.get(position); tempItem.setHidden(true); for (int i = 0; i < 101; i++) { tempItem.setProcess(i); dataList.set(position, tempItem); Message message = new Message(); message.arg1 = position; message.what = WHAT_REFRESH; DLog.d("发送消息" ); handler.sendMessage(message); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }).start(); }
然后handle发送消息:
private final int WHAT_REFRESH = 0 ; @SuppressLint("HandlerLeak") /** * 处理视图更新 */ private Handler handler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case WHAT_REFRESH: DLog.d("接收到消息" ); refreshItem(msg.arg1); break; default: break; } }; };
handler调用更新界面的方法,去更新界面.
/** * 更新指定的item * @param position */ public void refreshItem(int position){ DLog.d("更新界面" ); int first = listView.getFirstVisiblePosition(); View view = listView.getChildAt(position - first); getView(position, view, listView); }
更新指定的item,就是调用getView方法:
public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub Holder holder ; ButtonClick click; DLog.d("调用getView" ); if (convertView == null) { holder = new Holder(); convertView = LayoutInflater.from(context).inflate( R.layout.list_view_item, parent,false); click = new ButtonClick(position); holder.button = (Button) convertView.findViewById(R.id.button); holder.button.setOnClickListener(click); holder.textView = (TextView) convertView.findViewById(R.id.text_view); holder.progressBar = (ProgressBar) convertView.findViewById(R.id.progress); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } ListItem item = dataList.get(position); Log.d("----------", item.getProcess() + ""); holder.progressBar.setProgress(item.getProcess()); holder.textView.setText(item.getText()); if (item.isHidden()) { holder.textView.setVisibility(View.GONE); } else { holder.textView.setVisibility(View.VISIBLE); } return convertView; }
这就是整个流程.
在getView中,有个ButtonClick ,该类是给Button绑定的一个监听器.监听器内部记录item的位置Position.同样,当用户点击Button时会出发按钮事件,改变数据,更新item界面
/** * 按钮的点击事件 * @author Asia * */ public class ButtonClick implements OnClickListener{ /** * 记录按钮的位置 */ private int position; public ButtonClick(int position) { this.position = position; } @Override public void onClick(View v) { // TODO Auto-generated method stub //这里和itemClick方法内容一致,为了区分外部点击和按钮点击,故没调用同一个方法 int process = dataList.get(position).getProcess(); if (process > 0 && process < 100) { Toast.makeText(context, "任务正在进行", Toast.LENGTH_SHORT).show(); } else if (process == 0 || process == 100) { changeData(position); } } }
整个工程的代码在此需要的请下载:
ListViewDemo源代码