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

而我们一向写的自定义适配器,无非就是继承ArrayAdapter,或者继承自BaseAdapter,然后重写4个方法,前三个方法基本相同,不同在于getView方法,getView里面为了减少绑定和View的重建,又会引入一个静态类ViewHolder,我相信下面这段代码你一点见过不少。

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView; import java.util.List; /**
* 常见的ListView的Adapter适配器
* Created by 南尘 on 16-7-28.
*/
public class MyListAdapter extends BaseAdapter {
private Context context;
private List<Data> list; public MyListAdapter(Context context, List<Data> list) {
this.context = context;
this.list = list;
} @Override
public int getCount() {
return list == null ? 0 : list.size();
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
MyViewHolder holder = null;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.list_item,viewGroup,false);
holder = new MyViewHolder();
holder.iv = (ImageView) convertView.findViewById(R.id.item_image);
holder.tv = (TextView) convertView.findViewById(R.id.item_text);
convertView.setTag(holder);
} else {
holder = (MyViewHolder) convertView.getTag();
}
Data data = (Data) getItem(position);
holder.iv.setImageResource(data.getImageId());
holder.tv.setText(data.getText());
return convertView;
} public static class MyViewHolder {
ImageView iv;
TextView tv;
}
}

可以毫不犹豫地说这个东西我现在闭着眼睛都能流利地写出来,可见少了数百次是难以做到的。

有时候我们也想盛点时间去打点小地主,撩下小妹子,如果要是可以打造一个万能的适配器就好了。

仔细观察上面的Adapter,的确是前三个方法一样。我们要是可以全部抽出来就好了。所以可以抽出来,写一个泛型使其变成一个抽象的基类,继承自BaseAdapter.其子类只需要去关心其getView方法。

 public abstract class MyListAdapter<T> extends BaseAdapter {
private Context context;
private List<T> list; public MyListAdapter(Context context, List<T> list) {
this.context = context;
this.list = list;
} @Override
public int getCount() {
return list == null ? 0 : list.size();
} @Override
public Object getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
}
}

好像没什么不对,但是这也没解决多少问题呀,要是我们在写大项目的时候还可以抽点时间出来打LOL拿个首胜什么的就更好了。

再来看看getView方法,基本都是先判断ViewHolder是否为空,为空则去Inflate一个xml文件进来,再绑定下视图,设置一个标记,不为空的时候直接引用标记。

或许这里我们可以试一下在ViewHolder上做点什么。

我们要是想把ViewHolder提取出来,只能把每一个Item都固定在ViewHolder里面,而Item又不是固定的,怎么办?

要是我们可以把这个Item直接作为参数传进来就好了,可是传控件好像不能区分,仔细一想,我们能看到一个控件对应着一个id,这个好像可以用HashMap的键值对处理。

而键值由于是Int型的,在新的java API中明确表示在键值为Integer的HashMap中我们要用SparseArray作代替,这样不仅简单,而且性能更优。

我们尝试着封装一下ViewHolder

 public class ViewHolder {
//现在对于int作为键的官方推荐用SparseArray替代HashMap
private final SparseArray<View> views;
private int position;
private View convertView;
private Context context; private ViewHolder(Context context,ViewGroup parent, int layoutId, int position) {
this.context = context;
this.views = new SparseArray<>();
this.convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
convertView.setTag(this);
} /**
* 拿到一个ViewHolder对象
*/
public static ViewHolder get(View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(parent.getContext(),parent, layoutId, position);
}
return (ViewHolder) convertView.getTag();
} /**
* 通过控件的Id获取对于的控件,如果没有则加入views
*/
public <T extends View> T getView(int viewId) {
View view = views.get(viewId);
if (view == null) {
view = convertView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
}

这样的话我们的getView可能会变成这样。

 @Override
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder = ViewHolder.get(convertView, parent,
R.layout.list_item, position);
TextView mTitle = viewHolder.getView(R.id.id_tv_title);
mTitle.setText(((Data) list.get(position)).getText());
//这里就不设置ImageView了
return viewHolder.getConvertView();
}

好吧。与其这样。我们不如直接写在Activity中。

并且如果我们想设置东西也许可以在Holder里面设置,我们可以试一试。

封装后的ViewHolder是这样。

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import com.squareup.picasso.Picasso; /**
* 万能适配器的ViewHolder
* Created by 南尘 on 16-7-28.
*/
public class ViewHolder {
//现在对于int作为键的官方推荐用SparseArray替代HashMap
private final SparseArray<View> views;
private int position;
private View convertView;
private Context context; private ViewHolder(Context context,ViewGroup parent, int layoutId, int position) {
this.context = context;
this.views = new SparseArray<>();
this.convertView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
convertView.setTag(this);
} /**
* 拿到一个ViewHolder对象
*/
public static ViewHolder get(View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(parent.getContext(),parent, layoutId, position);
}
return (ViewHolder) convertView.getTag();
} /**
* 通过控件的Id获取对于的控件,如果没有则加入views
*/
public <T extends View> T getView(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;
} /**
* 设置字符串
*/
public ViewHolder setText(int viewId,String text){
TextView tv = getView(viewId);
tv.setText(text);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageResource(int viewId,int drawableId){
ImageView iv = getView(viewId);
iv.setImageResource(drawableId);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageBitmap(int viewId, Bitmap bitmap){
ImageView iv = getView(viewId);
iv.setImageBitmap(bitmap);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageByUrl(int viewId,String url){
Picasso.with(context).load(url).into((ImageView) getView(viewId));
// ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
// ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
return this;
} public int getPosition(){
return position;
}
}

上面的图片网络加载我用Picasso加载框架,这个网上很多图片加载框架,我前面博客也有很多Demo,大家可以自行查找。

再看看我们的万能适配器,这里我们把它写做一个抽象类,传入一个泛型作为参数。

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter; import java.util.List; /**
* 打造ListView的万能适配器
* Created by 南尘 on 16-7-28.
*/
public abstract class CommonAdaper<T> extends BaseAdapter {
private Context context;
private List<T> list; public CommonAdaper(Context context, List<T> list) {
this.context = context;
this.list = list;
} @Override
public int getCount() {
return list == null ? 0 : list.size();
} @Override
public T getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = ViewHolder.get(view,viewGroup,R.layout.list_item,i);
convert(holder,getItem(i));
return holder.getConvertView();
} public abstract void convert(ViewHolder holder,T item); }

再看看我们主页面怎么调用的。

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView; import java.util.ArrayList;
import java.util.List; public class MainActivity extends AppCompatActivity { private ListView listView;
private List<Data> list; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.main_lv);
initList(); listView.setAdapter(new CommonAdaper<Data>(this,list) {
@Override
public void convert(ViewHolder holder, Data item) {
holder.setText(R.id.item_text,item.getText());
if (item.getImageUrl() != null){
holder.setImageByUrl(R.id.item_image,item.getImageUrl());
}else {
holder.setImageResource(R.id.item_image,item.getImageId());
}
}
});
} private void initList() {
list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new Data("本地 "+i,R.mipmap.ic_launcher));
} for (int i = 0; i < 5; i++) {
list.add(new Data("网络 "+i,"http://pic.cnblogs.com/face/845964/20160301162812.png"));
}
}
}

最后上我写的两个xml

一个是Activity_main.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"
tools:context="com.example.nanchen.commonadapterforlistviewdemo.MainActivity"> <ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_lv"/>
</RelativeLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <ImageView
android:id="@+id/item_image"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@mipmap/ic_launcher"/> <TextView
android:id="@+id/item_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:text="内容"/> </LinearLayout>

这个你想怎么定义就想定义了。

本人亲测这个东西可以用,还没入坑的小伙伴赶快入坑吧。

明天我可能还会带来万能的RecyclerView的适配器,还请大家持续关注~~~~

————————————————————————————————————————————————————————————————————————————

7月30日补充:

今天在自己思考写最近大火的RecyclerView的万能适配器的时候参考这边的时候,发现在MainActivity中竟然不能设置其他的布局,才发现自己之前的逻辑有点问题,应该把Layout的ID也作为参数传到Adater去中。看来自己有时候想的也不是很周到,大家看的时候也要多加思考呀。

这是改动后的Adpter和ViewHolder

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter; import java.util.List; /**
* 打造ListView的万能适配器
* Created by 南尘 on 16-7-28.
*/
public abstract class CommonAdaper<T> extends BaseAdapter {
private Context context;
private List<T> list;
private LayoutInflater inflater;
private int itemLayoutId; public CommonAdaper(Context context, List<T> list,int itemLayoutId) {
this.context = context;
this.list = list;
this.itemLayoutId = itemLayoutId;
inflater = LayoutInflater.from(context);
} @Override
public int getCount() {
return list == null ? 0 : list.size();
} @Override
public T getItem(int position) {
return list.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = getViewHolder(position,convertView,parent);
convert(holder,getItem(position));
return holder.getConvertView();
} public abstract void convert(ViewHolder holder,T item); private ViewHolder getViewHolder(int position,View convertView,ViewGroup parent){
return ViewHolder.get(context,convertView,parent,itemLayoutId,position);
} }

思想里面应该很清楚了吧。

 package com.example.nanchen.commonadapterforlistviewdemo;

 import android.content.Context;
import android.graphics.Bitmap;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView; import com.squareup.picasso.Picasso; /**
* 万能适配器的ViewHolder
* Created by 南尘 on 16-7-28.
*/
public class ViewHolder {
//现在对于int作为键的官方推荐用SparseArray替代HashMap
private final SparseArray<View> views;
private View convertView;
private Context context; private ViewHolder(Context context,ViewGroup parent,int itemLayoutId,int position) {
this.context = context;
this.views = new SparseArray<>();
this.convertView = LayoutInflater.from(context).inflate(itemLayoutId,parent,false);
convertView.setTag(this);
} /**
* 拿到一个ViewHolder对象
*/
public static ViewHolder get(Context context,View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(context,parent, layoutId, position);
}
return (ViewHolder) convertView.getTag();
} /**
* 通过控件的Id获取对于的控件,如果没有则加入views
*/
public <T extends View> T getView(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;
} /**
* 设置字符串
*/
public ViewHolder setText(int viewId,String text){
TextView tv = getView(viewId);
tv.setText(text);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageResource(int viewId,int drawableId){
ImageView iv = getView(viewId);
iv.setImageResource(drawableId);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageBitmap(int viewId, Bitmap bitmap){
ImageView iv = getView(viewId);
iv.setImageBitmap(bitmap);
return this;
} /**
* 设置图片
*/
public ViewHolder setImageByUrl(int viewId,String url){
Picasso.with(context).load(url).into((ImageView) getView(viewId));
// ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(context));
// ImageLoader.getInstance().displayImage(url, (ImageView) getView(viewId));
return this;
}
}

同步重新同步至Github:https://github.com/nanchen2251/CommonAdapterListViewDemo

打造android偷懒神器———ListView的万能适配器的更多相关文章

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

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

  2. Xamarin.Android 使用 SimpleAdapter 打造 ListView 万能适配器

    第一步:创建 layout1.axml 来展示列表详细内容 <?xml version="1.0" encoding="utf-8"?> <L ...

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

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

  4. Android万能适配器Adapter-android学习之旅(74)

    万能适配器的代码的github地址是https://github.com/fengsehng/CommonAdapter 万能适配器的代码的github地址是https://github.com/fe ...

  5. 安卓开发笔记——打造万能适配器(Adapter)

    为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...

  6. Android进阶笔记10:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

  7. Android开发之万能适配器

    ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法 ...

  8. 打造android万能上拉下拉刷新框架——XRefreshView (二)

    打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下 ...

  9. Android进阶笔记09:Android 万能适配器

    1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...

随机推荐

  1. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  2. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  3. PHP以接口方式实现多重继承(完全模拟)--学习笔记

     1.UML类图: 2.PHP代码: <?php /** * Created by PhpStorm. * User: andy * Date: 16-11-23 * Time: 下午7:57 ...

  4. 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包

            微信支付教程系列之现金红包           最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...

  5. zookeeper源码分析之二客户端启动

    ZooKeeper Client Library提供了丰富直观的API供用户程序使用,下面是一些常用的API: create(path, data, flags): 创建一个ZNode, path是其 ...

  6. Android 几种消息推送方案总结

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6241354.html 首先看一张国内Top500 Android应用中它们用到的第三方推送以及所占数量: 现 ...

  7. js面向对象学习 - 对象概念及创建对象

    原文地址:js面向对象学习笔记 一.对象概念 对象是什么?对象是“无序属性的集合,其属性可以包括基本值,对象或者函数”.也就是一组名值对的无序集合. 对象的特性(不可直接访问),也就是属性包含两种,数 ...

  8. 手动导入swift三方danielgindi/Charts到OC工程中教程

    1.到github网址上下载zip压缩包https://github.com/danielgindi/Charts 2.然后将解压后的文件夹整个拖到自己的工程文件夹下(很多教程只让拖xcodeproj ...

  9. ORACLE中STATUS为INACTIVE但是SERVER为SHARED状态的会话浅析

    我们知道当ORACLE数据库启用共享服务器模式时,通过共享服务器模式连接到数据库的会话是有一些特征的.在v$session里面,其SERVER的状态一般为SHARED和NONE, 为SHARED时,表 ...

  10. Help Hanzo (素数筛+区间枚举)

    Help Hanzo 题意:求a~b间素数个数(1 ≤ a ≤ b < 231, b - a ≤ 100000).     (全题在文末) 题解: a~b枚举必定TLE,普通打表MLE,真是头疼 ...