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. 两个数据库通过DataTable实现差异传输

    两个主要方法 /// <summary>/// 用途:/// 用源表和目标表比较,返回差异的数据(目标表为参照物)/// /// 逻辑:/// 1.合并两个表/// 2.循环合并后得到的表 ...

  2. python3 logging笔记

    #coding:utf-8import logging logger = logging.getLogger("simple_example")#可以说是日志信息的名字吧,可以随便 ...

  3. java线程类图

    Executors创建不同类型的Executor, executor执行不同的runnable task Executor: Runnable:

  4. Angular JS ng-model对<select>标签无效的情况

    使用场景一: <select ng-if="item.award_type==1" id="award{{$index+1}}" name="X ...

  5. java——数组栈 ArrayStack

    栈的应用: undo操作-编辑器 系统调用栈-操作系统 括号匹配-编译器 以下是动态数组实现的数组栈: 定义动态数组: package Date_pacage; public class Array& ...

  6. 爬虫(GET)——爬baidu.com主页

    工具:python3 目标:www.baidu.com 工作流程: 1)反爬虫第一步:抓包工具fiddler抓取页面请求信息,得到User-Agent的值,用于重构urllib.request.Req ...

  7. pageX,clientX,offsetX,screenX,offsetLeft,style.left,offsetWidth,scrollWidth的区别以及使用详解

    https://www.cnblogs.com/echolun/p/9231760.html

  8. java字符串转Date

    public static Date StrToDate(String str) { SimpleDateFormat format = new SimpleDateFormat("yyyy ...

  9. cookie使用举例(添加购物车商品_移除购物车商品)

    之前介绍过cookie和session的原理和区别.下面举例说明一下cookie在实际项目中的使用.使用cookie实现购物车功能: 1.往购物车添加商品 2.从购物车里移除商品 主要是要点是:以产品 ...

  10. [转]js判断url是否有效

    本文转自:http://www.cnblogs.com/fumj/p/3490121.html 方法一:(仅适用于ie) function CheckStatus(url) { XMLHTTP = n ...