ListView加载性能优化---ViewHolder---分页
ListView是Android中一个重要的组件,可以使用它加列表数据,用户可以自己定义列表数据,同时ListView的数据加载要借助Adapter,一般情况下要在Adapter类中重写getCount(),getItem(),getItemId(),getView()四个方法。自定义列表项,以及数据的加载在getView()中处理。当ListView加载的列表项数据过多时,会占用大量的内存,影响性能,因此要对ListView进行优化。
getView的加载方法有3种形式,如下:
1.每次创建一个view,然后加载数据,加载速度慢
/**
* 1.每次都创建一个View
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.listview_item_two,null);
ImageView iv = (ImageView) view.findViewById(R.id.lv_listview_adapter_img);
TextView tv = (TextView) view.findViewById(R.id.tv_listview_adapter_name);
iv.setImageResource(icons[position]);
tv.setText(titles[position]);
return view;
}
2.当convertView不为空的时候直接重新使用convertView,为空时新建view,这样可以减少了很多不必要的View的创建,然后加载数据
/**
* 2.复用convertView,减少不必要的创建
* 当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.listview_item_two,null);
}
ImageView iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
TextView tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
iv.setImageResource(icons[position]);
tv.setText(titles[position]);
return convertView;
}
3.定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可
ViewHolder将需要缓存的view封装好,convertView的setTag才是将这些缓存起来供下次调用。 当你的listview里布局多样化的时候 viewholder的作用体现明显,效率再一次提高。 View的findViewById()方法也是比较耗时的,因此需要考虑只调用一次,之后就用View.getTag()方法来获得ViewHolder对象。
当加载100条数据时,采用分页,每页加载20条,相当于创建了20个convertview。再加载21-40这二十条时,不需要重新创建20个convertview。第21条复用第1条的convertView,第22条复用第2条的convertView.......
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if(convertView==null){
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.listview_item_two,null);
vh = new ViewHolder();
vh.iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
vh.tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
convertView.setTag(vh);
}else{
vh = (ViewHolder)convertView.getTag();
}
vh.iv.setImageResource(icons[position]);
vh.tv.setText(titles[position]);
return convertView;
}
static class ViewHolder{
ImageView iv;
TextView tv;
}
以下是一个亲测的Demo案例,代码及运行结果如下:
1.ListViewActivity.class
public class ListViewActivity extends AppCompatActivity {
private ListView listView_five;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view_adapter);
listView_five = (ListView) findViewById(R.id.lv_listview_adater);
listView_five.setAdapter(new MyAdapter(this));
listView_five.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(ListViewActivity.this,"position="+position,Toast.LENGTH_LONG).show();
}
});
}
static class MyAdapter extends BaseAdapter{
private String[] titles = {"title-1","title-2","title-3","title-4"};
private int[] icons = {android.R.drawable.ic_lock_idle_alarm,android.R.drawable.ic_lock_idle_alarm,
android.R.drawable.ic_lock_idle_alarm,android.R.drawable.ic_lock_idle_alarm};
private Context context;
public MyAdapter(Context context){
this.context = context;
}
@Override
public int getCount() {
return titles.length;
}
@Override
public Object getItem(int position) {
return titles[position];
}
@Override
public long getItemId(int position) {
return position;
}
/**
* 1.每次都创建一个View
*/
/*@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.listview_item_two,null);
ImageView iv = (ImageView) view.findViewById(R.id.lv_listview_adapter_img);
TextView tv = (TextView) view.findViewById(R.id.tv_listview_adapter_name);
iv.setImageResource(icons[position]);
tv.setText(titles[position]);
return view;
}*/
/**
* 2.复用convertView,减少不必要的创建
* 当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据
* @param position
* @param convertView
* @param parent
* @return
*/
/* @Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.listview_item_two,null);
}
ImageView iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
TextView tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
iv.setImageResource(icons[position]);
tv.setText(titles[position]);
return convertView;
}*/
/**
* 3.定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if(convertView==null){
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.listview_item_two,null);
vh = new ViewHolder();
vh.iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
vh.tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
convertView.setTag(vh);
}else{
vh = (ViewHolder)convertView.getTag();
}
vh.iv.setImageResource(icons[position]);
vh.tv.setText(titles[position]);
return convertView;
}
static class ViewHolder{
ImageView iv;
TextView tv;
}
}
}
2.activity_list_view_adapter.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"> <ListView
android:id="@+id/lv_listview_adater"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="10dp"
android:listSelector="#00ff00"
android:scrollbars="vertical|horizontal"
/>
</RelativeLayout>
3.listview_item_two.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <ImageView
android:id="@+id/lv_listview_adapter_img"
android:src="@mipmap/gradview_dog_one"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_listview_adapter_name"
android:text="拉布拉多"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>
三种方法的运行结果均相同,如下所示:

参考网址:http://blog.csdn.net/jacman/article/details/7087995
http://blog.csdn.net/pkxiuluo01/article/details/7380874
ListView分页的实现:
1.PageActivity.class
/**
* ListView分页
* 实现OnScrollListener监听
*/
public class PageActivity extends AppCompatActivity implements AbsListView.OnScrollListener{
private ListView listView_six;
private int index = 1;
private MyAdapter myAdapter;
private Vector<News> news = new Vector<>();//线程安全的容器
private static final int DATA_UPDATE = 0x1;//数据更新完成后的标记
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_page); listView_six = (ListView) findViewById(R.id.lv_listview_page);
listView_six.setOnScrollListener(this);
//引入加载缓冲布局,并添加到ListView的底部
View footView = getLayoutInflater().inflate(R.layout.load_item,null);
listView_six.addFooterView(footView);
initData();
myAdapter = new MyAdapter(this);
listView_six.setAdapter(myAdapter);
} //加载数据,每次加载10条
private void initData() {
for(int i = 0;i < 10;i++){
News n = new News();
n.setTitle("title"+index);
n.setContent("content"+index);
index++;
news.add(n);
}
} private int visibleLastIndex;//用来可显示的最后一条数据的索引
/**
*
* @param view
* @param scrollState 滚动状态
* SCROLL_STATE_IDLE:不再滚动时(停止)
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(myAdapter.getCount() == visibleLastIndex && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
new loadDataThread().start();
} } /**
*
* @param view
* @param firstVisibleItem 第一次显示的
* @param visibleItemCount 可显示的总量
* @param totalItemCount
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
visibleLastIndex = firstVisibleItem + visibleItemCount -1;
} //线程之间通讯机制
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case DATA_UPDATE:
//告知Adapter刷新数据
myAdapter.notifyDataSetChanged();
break;
default:
break;
}
}
}; //子线程通知UI线程
class loadDataThread extends Thread{
@Override
public void run() {
super.run();
//前10条数据加载完成时,再加载另外10条
initData();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通过Handler向主线程发送一个标记
handler.sendEmptyMessage(DATA_UPDATE);
}
}
//自定义Adapter
class MyAdapter extends BaseAdapter{
private Context context;
public MyAdapter(Context context){
this.context = context;
}
@Override
public int getCount() {
return news!=null?news.size():0;
} @Override
public Object getItem(int position) {
return news.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder vh;
if(convertView==null){
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.listview_item_three,null);
vh = new ViewHolder();
vh.tv_one = (TextView) convertView.findViewById(R.id.tv_page_title);
vh.tv_two = (TextView) convertView.findViewById(R.id.tv_page_content);
convertView.setTag(vh);
}else{
vh = (ViewHolder)convertView.getTag();
} News n = news.get(position);
vh.tv_one.setText(n.getTitle()+"---");
vh.tv_two.setText(n.getContent());
return convertView;
}
class ViewHolder{
TextView tv_one;
TextView tv_two;
}
}
}
2.activity_page.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.langdon.taiyang.androidtest.listview.PageActivity"> <ListView
android:id="@+id/lv_listview_page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="10dp"
android:listSelector="#00ff00"
android:scrollbars="vertical|horizontal"
/>
</LinearLayout>
3.load_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.langdon.taiyang.androidtest.listview.PageActivity"> <ListView
android:id="@+id/lv_listview_page"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="10dp"
android:listSelector="#00ff00"
android:scrollbars="vertical|horizontal"
/>
</LinearLayout>
4.listview_item_three.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"> <TextView
android:id="@+id/tv_page_title"
android:text="标题"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_page_content"
android:text="内容"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>
运行效果如下:

ListView加载性能优化---ViewHolder---分页的更多相关文章
- 安卓开发笔记——ListView加载性能优化ViewHolder
在前不久做安卓项目的时候,其中有个功能是爬取某网站上的新闻信息,用ListView展示,虽然做了分页,但还是觉得达不到理想流畅效果. 上网查阅了些资料,发现一些挺不错的总结,这里记录下,便于复习. 当 ...
- [转]listview加载性能优化ViewHolder
当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建. ListView加载数据都是在public View getView( ...
- android之 listview加载性能优化ViewHolder
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...
- listview加载性能优化ViewHolder
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局, 但当listview有大量的数据需要加载的时候 ...
- listview加载性能优化
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...
- H5 缓存机制浅析 移动端 Web 加载性能优化
腾讯Bugly特约作者:贺辉超 1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储, ...
- React 16 加载性能优化指南
关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...
- SPA 首屏加载性能优化之 vue-cli3 拆包配置
前言 现在已经是vue-cli3.x webpack4.x 的时代了,但是网上很多拆包配置还是一些比较低版本的. 本文主要是分享自己的拆包踩坑经验. 主要是用了webpack4 的 splitC ...
- Vue回炉重造之图片加载性能优化
前言 图片加载优化对于一个网站性能好坏起着至关重要的作用.所以我们使用Vue来操作一波.备注 以下的优化一.优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的 ...
随机推荐
- SQLite3源程序分析之虚拟机
前言 最早的虚拟机可追溯到IBM的VM/370,到上个世纪90年代,在计算机程序设计语言领域又出现一件革命性的事情——Java语言的出现,它与c++最大的不同在于它必须在Java虚拟机上运行.Java ...
- .Net Core Linux centos7行—IOC模块
.net core中可以说是用了全新的IOC模板,定义在Microsoft.Extensions.DependencyInjection下.提供了一套标准的接口.并提供了默认实现.并且大范围使用着,处 ...
- beanstalkd 消息队列
概况:Beanstalkd,一个高性能.轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Faceb ...
- Android换肤技术总结
原文出处: http://blog.zhaiyifan.cn/2015/09/10/Android%E6%8D%A2%E8%82%A4%E6%8A%80%E6%9C%AF%E6%80%BB%E7%BB ...
- cocos2d-x 3.5以后版本的 luasocket
cocos2d-x 3.5后使用luasocket:local SOCKET = require "socket"; 结果运行就报错:[LUA-print] USE " ...
- eclipse运行没问题,tomcat以脚本启动后插入数据库的中文会乱码
记一次部署工程的时候遇到的问题 部署war包到win7的时候发现,布上去后插入数据库的中文会乱码,然后发现用eclipse运行源码没问题,一开始以为是war打出来的时候编码错误,然后将eclipse的 ...
- begin
经历了一段时间的使用Github发表个人博客,我的感受就是很装逼,但是很麻烦--,因为都是自己手动弄的,还不如博客园方便,还有自己买了域名,但是SEO却提不上起,或者说压根就没有 --#,所以说,经过 ...
- PHP之:序列化和反序列化-serialize()和unserialize()
撰写日期:2016-7-7 10:56:40 参考PHP在线手册(php.net):http://php.net/manual/zh/function.serialize.php 1.序列化 seri ...
- JS中class和id的区别
class和id的区别 class用于css的,id用于js的. 1)class页面上可以重复.id页面上唯一,不能重复. 2)一个标签可以有多个class,用空格隔开.但是id只能有id.
- pgsql 建数据库注意事项
在用navacat建好表之后,需要主键自增的时候,把字段建好之后,可以使用下面的sql来建立主键自增. ALTER TABLE "public"."chart_sql&q ...