在调用adapter的notifydatasetchanged更新列表组件时候,实际上就是调用adpater的getView方法重新获取页面的各个元素的过程,因为调用notify的时候,填充页面的list数据源往往发生了变化,那么getView得到的数据也就不一样了,所以界面就会发生改变。例如,我定义一个apater类:
public class MyAdapter extends BaseAdapter { Context context; List<Pojo> pojos; public MyAdapter(Context context,List<Pojo> pojos){ this.context = context; this.pojos = pojos; } @Override
private getView(){
} }
这时候我在activity里传入一个list,OK没错,每当我传入的list放生改变的时候,调用notify刷新都没有错。
但是最近做工程的时候,我创建了一个nodetree类,为了方便,在adaper里使用的是nodetree的nodes的list,看代码
public class Nodetree extends LinearLayout{ public List<Node> nodes = new ArrayList<Node>; ..... }
public class MyAdapter extends BaseAdapter { Context context; List<Node> nodes; NodeTree tree; public MyAdapter(Context context,List<Node> nodes,NodeTree tree){ this.context = context; this.tree = tree; this.nodes = tree.nodes; } @Override private getView(){ } }
然后,我再nodeTree里边对list进行增删改查,然后通知adapter刷新,理论上应该没问题,但是删除时候却出现了问题,界面不刷新!没办法,最后只得将数据的形式重新改为了一图所示的格式,即数据源直接放在adapter里边,刷新是肯定没有问题的,而且这样做的耦合性会好很多。
第二,再来学习一下刷新单个列表项的方法吧,虽然目前为止还没有用到,但是难保将来不会用到,未雨绸缪,当然是极好的。
其实,单条刷新机制的核心就是如何找到自己要更新的item,并手动调用getview去更新。
adpter类,很简单,就是利用一个convertview
public class MyAdapter extends BaseAdapter { Context context; List<String> names; public MyAdapter(Context context,List<String> names){ this.context = context; this.names = names; } @Override public int getCount() { // TODO Auto-generated method stub return names.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return names.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub String name = names.get(position); if (convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.single_refresh, parent, false);//这个parent最好设置一下(parent为listview),否则有些布局情况下,设置为true会报addview isnot supported in adapterView,男人不能有孩子啦 } ((TextView)convertView).setText(name); return convertView; } }
然后在activity中写了一个refresh类,手动刷新需要更新的数据,这里需要用到几个平时不怎么见到的方法
public class MainActivity extends Activity { private ListView namesListView; private MyAdapter adapter; private List<String> names; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); names = new ArrayList<String>(); names.add("小李"); names.add("小刚"); names.add("小明"); names.add("小花"); names.add("小红"); names.add("小兰"); namesListView = (ListView) findViewById(R.id.nameList); adapter = new MyAdapter(this, names); namesListView.setAdapter(adapter); }
/**
*替换当前视野中的某个元素
**/ private void singleRefresh(int id){ if (namesListView != null) { int start = namesListView.getFirstVisiblePosition();//获取视野中的第一个元素(因为有些元素会被list刷过去) int end = namesListView.getLastVisiblePosition(); for (int i = start; i < end; i++) { if (id == namesListView.getItemIdAtPosition(i)) {//listview显示的只是position TextView view = (TextView) namesListView.getChildAt(i-start);//不能addview,却依然可以有孩子 names.set(i, "我变身超级赛亚人啦!"); adapter.getView(i, view, null);
//adapter.getView(i, view, namesListView);也可以
break; } } } } public void refresh(View v){ singleRefresh(0); } }
需要注意:在ListView中,使用getChildAt(index)的取值,只能是当前可见区域(列表可滚动)的子项!
即取值在 ListView.getFirstVisiblePosition()~ListView.getLastVisiblePosition()之间