大家有没有遇到过在不刷新listview,即调用notifyDataSetChanged()的情况下单独更新item.下面带大家按照google采用的方式单独更新item
代码如下:
MainActivity
public class MainActivity extends Activity implements OnItemClickListener{
ArrayList<String> list;
ListView listview;
ListViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview=(ListView) findViewById(R.id.listview);
init();
adapter=new ListViewAdapter(list,this);
listview.setAdapter(adapter);
listview.setOnItemClickListener(this);
}
public void init(){
list=new ArrayList<String>();
list.add("the item 1");
list.add("the item 2");
list.add("the item 3");
list.add("the item 4");
list.add("the item 5");
list.add("the item 6");
..........
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long id) {
adapter.updateSingleRow(listview,id);
}
}
activity_main.xml 只有一个ListView控件。
ListViewAdapter:
public class ListViewAdapter extends BaseAdapter{
ArrayList<String> list;
Context context;
public ListViewAdapter(ArrayList<String> list,Context context){
this.list=list;
this.context=context;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int arg0) {
return list.get(arg0);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int arg0, View convertView, ViewGroup viewGroup) {
ViewHolder holder;
if(convertView==null){
convertView=LayoutInflater.from(context).inflate(R.layout.listview_item, null, false);
holder=new ViewHolder();
holder.textView=(TextView) convertView.findViewById(R.id.item_text);
convertView.setTag(holder);
}else{
holder=(ViewHolder) convertView.getTag();
}
holder.textView.setText(list.get(arg0));
return convertView;
}
class ViewHolder{
TextView textView;
}
public void updateSingleRow(ListView listview,long id){
int firstPosition=listview.getFirstVisiblePosition();
int lasrPosition=listview.getLastVisiblePosition();
for(int i=firstPosition;i<=lasrPosition;i++){
if(listview.getItemIdAtPosition(i)==id){ //当传过来的id与遍历的id相同就更新
View view=listview.getChildAt(i-firstPosition); //如果可见的第一个item不是0
list.remove(i);
list.add(i,"我在更新数据");
getView(i,view,null);
}
}
}
}
这里解释下:
long id 表示item的id,这是与position是不同的概念。
listview.getFirstVisiblePosition(); 获取的屏幕上显示的第一条item的positon
listview.getLastVisiblePosition(); 获取屏幕上显示的最后一条item的position
getView(i,view,null) 可以实现单独的更新,注意参数view.
至此就可以实现单独跟新item了,同样的采用notifyDataSetChanged()同样可以实现。
疑问:如果我加上Header和Footer还会实现相同的效果吗?
在MainActivity的listview.setAdapter(adapter)之前添加如下语句:
View header=LayoutInflater.from(this).inflate(R.layout.listview_header,null); //很简单的布局
View footer=LayoutInflater.from(this).inflate(R.layout.listview_footer,null);
listview.addHeaderView(header);
listview.addFooterView(footer);
测试图:
上拉刷新之后:
通过测试发现当点击刷新之后,滑动之后,更改数据出现下滑的现象.
主要原因是:添加header和footer之后第一个position的item变成了header, 最后一个position的item变成footer
假如我点击的第3个position的item,在前面有一个header和1个item,通过调用updateSingleRow(),遍历之后调用getView(i,view null),这里需要注意getView()中的position只对应arraylist的index,不包含header和footer,所以这里传进去的i包含了header,导致arraylist集体下移了,所以实际上更新的是第4个position的值,当滑动时肯定还原,变成第四个position更改数据。
解决方式:
list.remove(i-1);
list.add(i-1,"我在更新数据"); //加入i=3,那么改变的 是集合中第四条数据,所以必须减去1
getView(i-1,view,null);
最终的结果正确
问题:按照错误的方式,为什么我初次点击的时候,数据更改是对的,但是当我上拉之后数据才会变化,刚开始按照前面的逻辑应该也会错位?