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---分页的更多相关文章

  1. 安卓开发笔记——ListView加载性能优化ViewHolder

    在前不久做安卓项目的时候,其中有个功能是爬取某网站上的新闻信息,用ListView展示,虽然做了分页,但还是觉得达不到理想流畅效果. 上网查阅了些资料,发现一些挺不错的总结,这里记录下,便于复习. 当 ...

  2. [转]listview加载性能优化ViewHolder

    当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建. ListView加载数据都是在public View getView( ...

  3. android之 listview加载性能优化ViewHolder

    在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...

  4. listview加载性能优化ViewHolder

    在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局, 但当listview有大量的数据需要加载的时候 ...

  5. listview加载性能优化

    在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...

  6. H5 缓存机制浅析 移动端 Web 加载性能优化

    腾讯Bugly特约作者:贺辉超 1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储, ...

  7. React 16 加载性能优化指南

    关于 React 应用加载的优化,其实网上类似的文章已经有太多太多了,随便一搜就是一堆,已经成为了一个老生常谈的问题. 但随着 React 16 和 Webpack 4.0 的发布,很多过去的优化手段 ...

  8. SPA 首屏加载性能优化之 vue-cli3 拆包配置

    前言 现在已经是vue-cli3.x    webpack4.x 的时代了,但是网上很多拆包配置还是一些比较低版本的. 本文主要是分享自己的拆包踩坑经验. 主要是用了webpack4 的 splitC ...

  9. Vue回炉重造之图片加载性能优化

    前言 图片加载优化对于一个网站性能好坏起着至关重要的作用.所以我们使用Vue来操作一波.备注 以下的优化一.优化二栏目都是我自己封装在Vue的工具函数里,所以请认真看完,要不然直接复制的话,容易出错的 ...

随机推荐

  1. Asp.net 设置GridView自适应列宽不变形

    动态绑定的GridView由于列数不固定,而列又太多,这样设置GridView固定宽度就不能满足需求了.为此整理了两种方法来达到GridView自适应列宽不变形的效果. //在GridView的行数据 ...

  2. .NET跨平台之旅:基于.NET Core改写EnyimMemcached,实现Linux上访问memcached缓存

    注:支持 .NET Core 的 memcached 客户端 EnyimMemcachedCore 的 NuGet 包下载地址:https://www.nuget.org/packages/Enyim ...

  3. 齐夫定律, Zipf's law,Zipfian distribution

    齐夫定律(英语:Zipf's law,IPA英语发音:/ˈzɪf/)是由哈佛大学的语言学家乔治·金斯利·齐夫(George Kingsley Zipf)于1949年发表的实验定律. 它可以表述为: 在 ...

  4. HDU3068 回文串 Manacher算法

    好久没有刷题了,虽然参加过ACM,但是始终没有融会贯通,没有学个彻底.我干啥都是半吊子,一瓶子不满半瓶子晃荡. 就连简单的Manacher算法我也没有刷过,常常为岁月蹉跎而感到后悔. 问题描述 给定一 ...

  5. sql server生成递归日期

    WITH Date AS ( SELECT CAST('2008-08-01' AS DATETIME) da UNION ALL FROM Date WHERE da < '2008-08-2 ...

  6. How to Disable Strict SQL Mode in MySQL 5.7

    If your app was written for older versions of MySQL and is not compatible with strict SQL mode in My ...

  7. 如何把Spring制作成jar包,然后在项目里运行。

    第一步:首先我们先把Spring的代码准备好.如图一 (图1). 第二步:我们在桌面新建一个文件夹,如图二 (图2). 我们要在这个文件夹里新建两个夹,一个文件夹是你项目的包名,也就是我们图1的aop ...

  8. java面向对象---对象容器

    泛型类--ArrayList<>; 2.对象数组中的每个元素都是对象的管理者而并非对象本身!!!!! 3.java类的基本数据类型 基本数据类型 包装类 byte Byte short S ...

  9. canvas-渐变文字

    html要求: <body onload="draw('canvas');"> body这里的onload一定要写,在这个处理模式下,是在body这里执行加载页面完成后 ...

  10. UOJ59 WC2013 小Q运动季

    题意:给一个模线性方程组,构造解满足尽量多的方程. 直接枚举. 模数两两互质,先排除无解的,然后CRT,然而要高精,上python. 直接高消,有完美解. 2^20暴搜. 分解模数,对每个质数高消,C ...