ListView性能优化
Posted evolutionoflicorice
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ListView性能优化相关的知识,希望对你有一定的参考价值。
ListView在ScrollView中无法正确计算它的大小, 故不能显示正常的条目。
解决办法有:
1.重写ListView, 覆盖onMeasure()方法。
1 public class WrapperListView extends ListView { 2 public WrapperListView(Context context) { 3 super(context); 4 } 5 public WrapperListView(Context context, AttributeSet attrs) { 6 super(context, attrs); 7 } 8 public WrapperListView(Context context, AttributeSet attrs, int defStyleAttr) { 9 super(context, attrs, defStyleAttr); 10 } 11 public WrapperListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 12 super(context, attrs, defStyleAttr, defStyleRes); 13 } 14 /** 15 * 重写该方法,达到使ListView适应ScrollView的效果 16 */ 17 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 18 int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); 19 super.onMeasure(widthMeasureSpec, expandSpec); 20 } 21 }
2.动态设置LIstView的高度,不需要重写LIstView
只需要在setAdapter之后调用如下方法即可:
public void setListViewHeightBasedOnChildren(ListView listView) { // 获取ListView对应的Adapter ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { return; } int totalHeight = 0; for (int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目 View listItem = listAdapter.getView(i, null, listView); // 计算子项View 的宽高 listItem.measure(0, 0); // 统计所有子项的总高度 totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); // listView.getDividerHeight()获取子项间分隔符占用的高度 // params.height最后得到整个ListView完整显示需要的高度 listView.setLayoutParams(params); }
另外,这时,这时最好给ListView之外嵌套一层LinearLayout,不然有时候这种方法会失效。
最后,尽量避免ScrollView嵌套Listview,可使用使用listview的addHeader() 函数来实现预期效果或者利用布局的特性达到预期效果。
ListView就是一个将数据集合以动态滚动的方式展示到用户界面的View
ListView的父类AbsListView中的内部类RecycleBin(防止ListView出现oom)
优化:
1. getview中的convertView中起到缓存作用,复用convertView,对convertView进行判空,为空则初始化,从而减少了很多不必要的View的创建、减少findViewById的次数
2.采用ViewHolder模式缓存item条目的引用,减少多次findViewByID的次数
3.避免在getView方法中做耗时操作
3.给listView设置滚动监听器 根据不同状态 不同处理数据 分批分页加载 根据listView的状态去操作,比如当列表快速滑动时不去开启大量的异步任务去请求图片
6.尽量能保证 Adapter 的 hasStableIds() 返回 true 这样在 notifyDataSetChanged() 的时候,如果item内容并没有变化,ListView 将不会重新绘制这个 View,达到优化的目的
7.在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。 由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现。
9.ListView 中元素避免半透明: 半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。
方法一:把套在里面的ListVew 不让获取焦点即可。listview.setFocusable(false);注意:在xml布局里面设置android:focusable=“false”不生效
方法二:myScrollView.smoothScrollTo(0,0);
1.继承自LIstView实现OnScrollListener
实现OnScrollListener 接口重写onScrollStateChanged 和onScroll方法,
使用onscroll方法实现”滑动“后处理检查是否还有新的记录,如果有,调用 addFooterView,添加记录到adapter, adapter调notifyDataSetChanged 更新数据;如果没有记录了,把自定义的mFooterView去掉。使用onScrollStateChanged可以检测是否滚到最后一行且停止滚动然后执行加载
2.头部和尾部都是单独的两个继承自LinearLayout布局,通过LIstView的addHeaderView()和addFooterView()两个方法把其加载到LIstView中
3.必须实现3个构造方法,每个方法都要实现initView()
4.Visibility实现头部和底部布局显示与隐藏
3.Listview里有Button就点不动了你知道吗
当ListView的Item中包含button,item点击事件与Button控件(button换成TextView不会冲突)点击冲突解决办法
1.不再对item进行监听,而是在adapter中监听整个item布局convertView.setOnClickListener()实现item的点击事件
2.在item的布局文件中给button设置属性android:focusable="false"以防button抢占listview的点击
4.ListView图片异步加载实现思路
1.先从内存缓存中获取图片显示(内存缓冲)
2.获取不到的话从SD卡里获取(SD卡缓冲,,从SD卡获取图片是放在子线程里执行的,否则快速滑屏的话会不够流畅)
3.都获取不到的话从网络下载图片并保存到SD卡同时加入内存并显示(视情况看是否要显示)
这不是Android的优化,而是Java提倡的优化,
如果声明成员类不要求访问外围实例,就要始终把static修饰符放在它的声明中,使它成为静态成员类,而不是非静态成员类。
因为非静态成员类的实例会包含一个额外的指向外围对象的引用,保存这份引用要消耗时间和空间,并且导致外围类实例符合垃圾回收时仍然被保留。如果没有外围实例的情况下,也需要分配实例,就不能使用非静态成员类,因为非静态成员类的实例必须要有一个外围实例。
以上是关于ListView性能优化的主要内容,如果未能解决你的问题,请参考以下文章
《Android开发艺术探索》之Android性能优化ListView和RecyclerView(十七)