ListView如何优化

  • 复用convertView缓存(减少ListView绘制).
  • 自定义静态类ViewHolder(减少findViewById次数),通过setTag()、getTag()获取holder实例.
  • 使用分页加载.
  • 使用软引用WeakReference引用ImageView对象:当item划出屏幕,可以释放对大图片的引用,节省内存,提高效率.
  • 另外对图片还可以使用LruCache和三级缓存来优化.

正常使用方式

public class MyAdapter extends BaseAdapter {

    private LayoutInflater mInflater;
private Context ctx;
private List<String> mDatas; public MyAdapter(Context ctx, List<String> mDatas) {
mInflater = LayoutInflater.from(ctx);
this.ctx = ctx;
this.mDatas = mDatas;
} @Override
public int getCount() {
return mDatas.size(); // 固定
} @Override
public Object getItem(int position) {
return mDatas.get(position); // 固定
} @Override
public long getItemId(int position) {
return position; // 固定
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) { // 复用convertView缓存
convertView = mInflater.inflate(R.layout.item_str, null); // 条目布局
holder = new ViewHolder();
holder.tv = (TextView) convertView.findViewById(R.id.tv); // holder存储控件
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv.setText(mDatas.get(position));
return convertView;
} private final class ViewHolder {
TextView tv;
}
}

上述代码大家都很熟悉,基本遇到就是一套,都写烂了,分析一下

  • 复写的三个方法都是固定的,很好抽取.
  • getView中通过set、get处理ViewHolder对象可以抽取.
  • holder中的findViewById可以抽取.

提炼

PART_A:Adapter

package com.catface.cadapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List; /** * @desc 使用泛型,接收不同类型的对象 */
public abstract class CAdapter<T> extends BaseAdapter {
protected Context ctx;
protected List<T> datas;
protected LayoutInflater inflater;
private int layoutId; // arg1-3:上下文 | 集合<泛型bean> | 条目布局
public CAdapter(Context ctx, List<T> datas, int layoutId) {
this.ctx = ctx;
this.datas = datas;
this.inflater = LayoutInflater.from(ctx);
this.layoutId = layoutId;
} @Override public int getCount() {
return datas == null ? 0 : datas.size();
} @Override public T getItem(int position) {
return datas == null ? null : datas.get(position);
} @Override public long getItemId(int position) {
return position;
} /** * @desc 1.获取ViewHolder对象(上下文、复用缓存、父布局、条目布局) */
@Override public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = ViewHolder.get(ctx, convertView, parent, layoutId, position);
convert(holder, getItem(position)); // ------>> 暴露抽象方法
return holder.getConvertView(); // 设置结束各个组件,返回ViewHolder对象方便继续设置控件值
} /** * @desc 暴露出去并传入holder与bean:拿着控件设置值 */
public abstract void convert(ViewHolder holder, T t);
}

PART_B:ViewHolder

package com.catface.cadapter;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.util.Linkify;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.widget.Checkable;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RatingBar;
import android.widget.TextView; /** * @desc 待修复问题: * * 1.CheckBox选中错位(复用convertView所致) √ * a.在Bean中添加isChecked字段 * b.在ListView中用ArrayList数组记录holder中当前选中的CheckBox * * 2.图片显示错位 × * * 3.上拉刷新 + 下拉加载 × */
public class ViewHolder {
private Context ctx; // 上下文
private View convertView; // 复用缓存
private int mLayoutId; // 条目布局
private SparseArray<View> views; // 各组件及对应id(SparseArray代替HashMap,提高效率)
private int position; public ViewHolder(Context ctx, ViewGroup parent, int layoutId, int position) {
this.ctx = ctx;
this.convertView = LayoutInflater.from(ctx).inflate(layoutId, parent, false);
this.mLayoutId = layoutId;
this.views = new SparseArray<View>();
this.position = position;
this.convertView.setTag(this);
} /** * @desc 通过setTag()和getTag()来获取ViewHolder对象 */
public static ViewHolder get(Context ctx, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(ctx, parent, layoutId, position);
} else {
ViewHolder holder = (ViewHolder) convertView.getTag();
holder.position = position;
return holder;
}
} /** * @desc 获取当前holder的position */
public int getPosition() {
return position;
} public int getLayoutId() {
return mLayoutId;
} /** * @desc 通过viewId获取控件 */
@SuppressWarnings("unchecked")
public <T extends View> T getViewByViewId(int viewId) {
View view = views.get(viewId);
if (view == null) {
view = convertView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
} public View getConvertView() {
return convertView;
} /************************************************ PS:图片可以使用第三方工具类加载图片 ************************************************/ /** 设置TextView文本 */
public ViewHolder setText(int viewId, String text) {
((TextView) getViewByViewId(viewId)).setText(text);
return this;
} /** 设置TextView颜色 */
public ViewHolder setTextColor(int viewId, int textColor) {
((TextView) getViewByViewId(viewId)).setTextColor(textColor);
return this;
} /** 设置TextView颜色 */
public ViewHolder setTextColorRes(int viewId, int textColorRes) {
((TextView) getViewByViewId(viewId)).setTextColor(ctx.getResources().getColor(textColorRes));
return this;
} /** 设置文本字体 */
public ViewHolder setTypeface(Typeface typeface, int... viewIds) {
for (int viewId : viewIds) {
TextView view = getViewByViewId(viewId);
view.setTypeface(typeface);
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
}
return this;
} /** 设置图片:资源id */
public ViewHolder setImageResource(int viewId, int resId) {
((ImageView) getViewByViewId(viewId)).setImageResource(resId);
return this;
} /** 设置图片:Bitmap */
public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
((ImageView) getViewByViewId(viewId)).setImageBitmap(bitmap);
return this;
} /** 设置图片:Drawable */
public ViewHolder setImageDrawable(int viewId, Drawable drawable) {
((ImageView) getViewByViewId(viewId)).setImageDrawable(drawable);
return this;
} /** 设置背景色 */
public ViewHolder setBackgroundColor(int viewId, int color) {
getViewByViewId(viewId).setBackgroundColor(color);
return this;
} /** 设置背景色 */
public ViewHolder setBackgroundRes(int viewId, int backgroundRes) {
getViewByViewId(viewId).setBackgroundResource(backgroundRes);
return this;
} @SuppressLint("NewApi")
public ViewHolder setAlpha(int viewId, float value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getViewByViewId(viewId).setAlpha(value);
} else {
// Pre-honeycomb hack to set Alpha value
AlphaAnimation alpha = new AlphaAnimation(value, value);
alpha.setDuration(0);
alpha.setFillAfter(true);
getViewByViewId(viewId).startAnimation(alpha);
}
return this;
} /** 设置可见状态 */
public ViewHolder setVisible(int viewId, boolean visible) {
getViewByViewId(viewId).setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
} public ViewHolder linkify(int viewId) {
TextView view = getViewByViewId(viewId);
Linkify.addLinks(view, Linkify.ALL);
return this;
} /** 设置进度 */
public ViewHolder setProgress(int viewId, int progress) {
((ProgressBar) getViewByViewId(viewId)).setProgress(progress);
return this;
} /** 设置最大进度 */
public ViewHolder setMax(int viewId, int max) {
ProgressBar view = getViewByViewId(viewId);
view.setMax(max);
return this;
} /** 设置进度、最大进度 */
public ViewHolder setProgress(int viewId, int progress, int max) {
ProgressBar view = getViewByViewId(viewId);
view.setMax(max);
view.setProgress(progress);
return this;
} public ViewHolder setRating(int viewId, float rating) {
RatingBar view = getViewByViewId(viewId);
view.setRating(rating);
return this;
} public ViewHolder setRating(int viewId, float rating, int max) {
RatingBar view = getViewByViewId(viewId);
view.setMax(max);
view.setRating(rating);
return this;
} public ViewHolder setTag(int viewId, Object tag) {
View view = getViewByViewId(viewId);
view.setTag(tag);
return this;
} public ViewHolder setTag(int viewId, int key, Object tag) {
View view = getViewByViewId(viewId);
view.setTag(key, tag);
return this;
} public ViewHolder setChecked(int viewId, boolean checked) {
Checkable view = (Checkable) getViewByViewId(viewId);
view.setChecked(checked);
return this;
} /** 设置点击事件 */
public ViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
getViewByViewId(viewId).setOnClickListener(listener);
return this;
} /** 设置触摸事件 */
public ViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) {
getViewByViewId(viewId).setOnTouchListener(listener);
return this;
} /** 设置长按事件 */
public ViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) {
getViewByViewId(viewId).setOnLongClickListener(listener);
return this;
}
}

PART_C:多条目的Adapter

  • 接口
package com.catface.cadapter;

/** * @desc 多条目ListView的Adapter接口 */
public interface IMultiCAdapter<T> {
int getLayoutId(int position, T t); int getViewTypeCount(); int getItemViewType(int postion, T t);
}
  • 具体Adapter
package com.catface.cadapter;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import java.util.List; /** * @desc 多条目的Adapter */
public abstract class MultiCAdapter<T> extends CAdapter<T> { protected IMultiCAdapter<T> mMultiItemTypeSupport; public MultiCAdapter(Context context, List<T> datas, IMultiCAdapter<T> multiItemTypeSupport) {
super(context, datas, -1);
this.mMultiItemTypeSupport = multiItemTypeSupport;
} @Override public int getViewTypeCount() {
if (mMultiItemTypeSupport != null) {
return mMultiItemTypeSupport.getViewTypeCount();
}
return super.getViewTypeCount();
} @Override public int getItemViewType(int position) {
if (mMultiItemTypeSupport != null) {
return mMultiItemTypeSupport.getItemViewType(position, datas.get(position));
}
return super.getItemViewType(position); } @Override public View getView(int position, View convertView, ViewGroup parent) {
if (mMultiItemTypeSupport == null) {
return super.getView(position, convertView, parent);
}
int layoutId = mMultiItemTypeSupport.getLayoutId(position, getItem(position));
ViewHolder viewHolder = ViewHolder.get(ctx, convertView, parent, layoutId, position);
convert(viewHolder, getItem(position));
return viewHolder.getConvertView();
}
}

提炼成果

  • 普通条目调用方式
setListAdapter(new CAdapter<Person>(getActivity(), datas, R.layout.item_fragment1) {
@Override
public void convert(ViewHolder viewHolder, Person person) {
viewHolder.setText(R.id.tv_name, person.getName()).setText(R.id.tv_age, person.getAge() + "").setImageResource(R.id.iv_icon, person.getIcon());
}
});
  • 带CheckBox等控件,解决其抢占item事件的方法

    • 条目布局父控件:android:descendantFocusability="blocksDescendants"
    • CheckBox:android:focusable="false"
setListAdapter(new CAdapter<Person>(getActivity(), datas, R.layout.item_fragment1up) {

    private List<Integer> points = new ArrayList<Integer>();

    @Override
public void convert(final ViewHolder viewHolder, Person person) {
viewHolder.setText(R.id.tv_name, person.getName()).setText(R.id.tv_age, person.getAge() + "").setImageResource(R.id.iv_icon, person.getIcon()); final CheckBox cb = (CheckBox) viewHolder.getViewByViewId(R.id.cb_f1up);
cb.setChecked(false); // 先置为false
if (points.contains(viewHolder.getPosition())) {
cb.setChecked(true);
}
cb.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (cb.isChecked()) {
points.add(viewHolder.getPosition());
} else {
points.remove((Integer) viewHolder.getPosition());
}
}
});
}

Android_ListView适配器的更多相关文章

  1. Android—万能ListView适配器

    ListView是开发中最常用的控件了,但是总是会写重复的代码,浪费时间又没有意义. 最近参考一些资料,发现一个万能ListView适配器,代码量少,节省时间,总结一下分享给大家. 首先有一个自定义的 ...

  2. 打造android偷懒神器———ListView的万能适配器

    如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示ListView,当然,写N个自定义的适配器也是情理之中.虽说程序员本身就是搬砖,做这些枯燥无味的重复的事情也是理所当然,但 ...

  3. 打造android偷懒神器———RecyclerView的万能适配器

    转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html 很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时 ...

  4. ListView和Adapter数据适配器的简单介绍

    ListView 显示大量相同格式数据 常用属性: listSelector            listView每项在选中.按下等不同状态时的Drawable divider            ...

  5. Android应用项目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三种适配器

    一.写在前面: 本次我们来讲解一下Android应用中三个适配器:BaseAdapter.SimpleAdapter和ArrayAdapter.其中常见的是BaseAdapter,也是个人推荐使用的适 ...

  6. Adapt适配器

    为接口提供所有的空实现,让使用者仅仅覆盖需要的部分: 本思想肯定有问题,慢慢考究 frame.addWindowListener(new WindowAdapter() { @Override pub ...

  7. Android之ListView性能优化——一行代码绑定数据——万能适配器

    如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...

  8. 【Android自学日记】两种适配器的使用

    ArrayAdapter适配器: (1)用于显示基本的文字内容 (2)基本使用过程:新建适配器---创建或加载数据源---适配器加载数据源---视图加载适配器 ArrayAdapter(上下文,当前L ...

  9. OC编程之道-接口适配之适配器

    已有的类与新的接口之间不兼容的问题相当普遍,人们已为它找到了一个解决方案.这个解决方案就是适配器. 1 何为适配器 what 适配器的主要作用是把被适配者的行为传递给管道另一端的客户端. 将一个类的接 ...

随机推荐

  1. 转 Comparison of Red Hat and Oracle Linux kernel versions and release strings

    Originally derived from Red Hat Enterprise Linux (RHEL), Oracle Linux (OL) contains minor difference ...

  2. swagger demo code

    //Application 开启注解 @EnableSwagger2public class Application { public static void main(String[] args) ...

  3. getopt 学习

    https://www.cnblogs.com/qingergege/p/5914218.html

  4. 数据结构---Java---ArrayList

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...

  5. inventor安装失败怎样卸载安装inventor 2017?

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...

  6. DRF之权限认证频率组建

    认证组件 很久很久以前,Web站点只是作为浏览服务器资源(数据)和其他资源的工具,甚少有什么用户交互之类的烦人的事情需要处理,所以,Web站点的开发这根本不关心什么人在什么时候访问了什么资源,不需要记 ...

  7. 在rails 中使用mysql 出现Mysql::Error: Incorrect string value: 的问题

    这是因为你在做数据库的操作中有非英文的问题,之后gem mysql2 处理中文必须要数据库也指定是utf-8 才比较好处理 解决的方法很简单,将数据库每张表都转化成utf-8即可,如果数据库没有什么重 ...

  8. C/C++中 static 的作用

    在C中,有三个作用: 1.修饰全局变量: 作用是隐藏,也就是这个全局变量仅在本文件中可见. 2.修饰局部变量: 作用是扩展变量的生存期,令这个局部变量成为静态的. 3.修饰函数: 作用是隐藏,将此函数 ...

  9. 《nginx 二》深入理解nginx的各项配置

    Nginx应用场景 1.http服务器.Nginx是一个http服务可以独立提供http服务.可以做网页静态服务器. 2.虚拟主机.可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机. 3. ...

  10. Graphics绘制类及打印机设置相关

    Graphics 有两个多个方法 这里面介绍3个: 1.Graphics.drawString():绘制.画字符串........... e.Graphics.DrawString("新乡市 ...