ListView 局部刷新
来源:互联网 发布:mac 下载ipython 编辑:程序博客网 时间:2024/05/18 02:45
概述
在使用ListView的时候,我们都会对列表数据进行更新,当数据变化时,我们会调用adapter的notifyDataSetChange方法去刷新列表。但是,该刷新方法是使整个列表都更新一遍(调用了adapter的getView方法)。而,我们往往只是更新了item中的某一项数据,如果刷新整个列表是不是显得太过于浪费了,特别是对于列表中有图片要显示的情况下,就会造成每次notifyDataSetChange图片会闪烁抖动。本文意在解决该问题,让数据更新只在局部。
解决方案
- 情景再现
下面例子的效果是,列表数据显示的是一系列数字,点击列表的item项时,该列表数字加1。那么一般的代码实现如下:
定义一个adapter
MyAdapter.java
public class MyAdapter extends BaseAdapter{ private Context context; private List<Integer> datas; public MyAdapter(Context context,List<Integer> datas){ this.context = context; this.datas = datas; } @Override public int getCount() { if(datas != null){ return datas.size(); } return 0; } @Override public Integer getItem(int position) { return datas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ convertView = LayoutInflater.from(context).inflate(R.layout.item_adapter,parent,false); holder = new ViewHolder(); holder.textView = (TextView) convertView.findViewById(R.id.textview); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(String.valueOf(getItem(position))); return convertView; } private class ViewHolder{ TextView textView; }}
item 布局这里只是简单的一个TextView
item_adapter.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/textview" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="45dp" android:textSize="18sp" android:gravity="center" android:textColor="@android:color/black" /></LinearLayout>
activity的布局activity_listview.xlm
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent"/></LinearLayout>
数据显示
public class ListViewTest extends Activity{ ListView mListView; MyAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listview); mListView = (ListView) findViewById(R.id.listview); final List<Integer> datas = new ArrayList<Integer>(); for (int i=1;i<10;i++){ datas.add(i); } adapter = new MyAdapter(this,datas); mListView.setAdapter(adapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { int data = datas.get(position); data = data+1; datas.set(position,data); adapter.notifyDataSetChanged(); } }); }}
这里主要是给ListView设置了setOnItemClickListener事件,然后进行+1处理,最后调用adapter的notifyDataSetChanged刷新数据。
好了,以上是我们一般的传统做法,下面我们看下如何实现ListView的局部刷新。
- ListView局部刷新实现
在adapter里定义一个方法notifyDataSetChangedAt(View view,int position),然后在该方法处理逻辑
例如本例子如下:
public void notifyDataSetChangedAt(View view,int position) { if(view != null){ int data = datas.get(position); data = data+1; datas.set(position,data); TextView textView = (TextView) view.findViewById(R.id.textview); textView.setText(String.valueOf(data)); } }
然后在外部调用,实现调用,这里有两种场景,实现方法不同。
- 第一种,在当前ListView点击item进行刷新
这种场景是属于比较常规的,实现起来也是比较简单的,如下:
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { /*int data = datas.get(position); data = data+1; datas.set(position,data); adapter.notifyDataSetChanged();*/ adapter.notifyDataSetChangedAt(view,position); }});
只要在ListView的setOnItemClickListener调用adapter的notifyDataSetChangedAt即可
- 第二种,在‘详情页’进行操作后,需要刷新ListView
第二种比较复杂一点,和业务关系紧密,一般业务场景是这样的:比如微博,在微博详情页,我点赞了,那么微博的列表相应的item的赞数要加1,这种场景的复杂在于,业务操作点与ListView脱离,不知要更新哪个item,但是,一般我们的业务module都有自己的一个id,通过该id我们就可以计算出item的位置。
修改一下adapter的数据类型,增加module
public class MyModule { private int id; private int count; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getCount() { return count; } public void setCount(int count) { this.count = count; }}
然后修改MyAdapter的数据类型为MyModule
public class MyAdapter extends BaseAdapter{ private Context context; private List<MyModule> datas; public MyAdapter(Context context,List<MyModule> datas){ this.context = context; this.datas = datas; } @Override public int getCount() { if(datas != null){ return datas.size(); } return 0; } @Override public MyModule getItem(int position) { return datas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView == null){ convertView = LayoutInflater.from(context).inflate(R.layout.item_adapter,parent,false); holder = new ViewHolder(); holder.textView = (TextView) convertView.findViewById(R.id.textview); convertView.setTag(holder); }else { holder = (ViewHolder) convertView.getTag(); } holder.textView.setText(String.valueOf(getItem(position).getCount())); return convertView; } private class ViewHolder{ TextView textView; } /** * 局部刷新 */ public void notifyDataSetChangedAt(View view,int position) { if(view != null){ MyModule data = datas.get(position); data.setCount(data.getCount()+1); datas.set(position,data); TextView textView = (TextView) view.findViewById(R.id.textview); textView.setText(String.valueOf(data.getCount())); } }}
修改activity
public class ListViewTest extends Activity{ ListView mListView; MyAdapter adapter; List<MyModule> datas = new ArrayList<MyModule>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listview); mListView = (ListView) findViewById(R.id.listview); for (int i=0;i<10;i++){ MyModule module = new MyModule(); module.setId(i); module.setCount(i+1); datas.add(module); } adapter = new MyAdapter(this,datas); mListView.setAdapter(adapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { /*int data = datas.get(position); data = data+1; datas.set(position,data); adapter.notifyDataSetChanged();*/ //adapter.notifyDataSetChangedAt(view,position); onListViewItemClick(datas.get(position)); } }); } private void onListViewItemClick(MyModule myModule){ //获取屏幕中ListView可见部分的第一个item位置索引 final int firstPos = mListView.getFirstVisiblePosition(); //循环遍历 for (int i = 0; i < datas.size(); i++) { MyModule module = datas.get(i); if (myModule != null && myModule.getId() == module.getId()) { View v = mListView.getChildAt(i - firstPos); adapter.notifyDataSetChangedAt(v, i); break; } } }}
我这里没有‘详情页’,通过ListView的ItemClickListener事件模拟了。最重要的方法是onListViewItemClick。思路:一般我们点击item进详情时,该item是处于在屏幕可见的,所以为了减少遍历次数,我们计算了ListView的第一个可见item的位置,然后通过比较是否是同一个module id实现局部刷新。
注意:一般使用场景是,详情页进行操作并更新module之后,通过setResult将module传给onActivityResult,然后调用onListViewItemClick(MyModule myModule)
- Android ListView 局部刷新
- listView局部刷新
- ListView局部刷新
- ListView局部刷新
- listview的局部刷新
- listview局部刷新
- ListView 局部刷新备忘
- Android ListView局部刷新
- ListView 局部刷新
- ListView的局部刷新
- listview 局部刷新
- ListView的局部刷新
- ListView局部刷新
- listview的局部刷新
- ListView的局部刷新
- listview的局部刷新
- ListView中的局部刷新
- android listview 局部刷新
- SQL Server 2005 2008 清空删除日志文件 130G日志 10秒内变10M
- 堆栈与队列
- markedTextRange理解及使用 计算长度
- cc2640看门狗
- ActiveMQ 即时通讯服务 浅析
- ListView 局部刷新
- ubuntu编译android源码出现的问题记录
- JSONObject 和 JSONArray
- mac下安装javaHL not available的解决方法
- JPUSH后台极光推送
- java 反射调用Service导致Spring注入Dao失效
- 华为面试笔试题
- TCP三次握手和四次挥手详解
- 关于Android使用Xutils的WebView保存Cookie登录