打造android偷懒神器———ListView的万能适配器
如果你去做任何一个项目,我相信你都会跟我有一样的经历,最最普遍的就是列表显示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的万能适配器的更多相关文章
- 打造android偷懒神器———RecyclerView的万能适配器
转载请注明出处谢谢:http://www.cnblogs.com/liushilin/p/5720926.html 很不好意思让大家久等了,本来昨天就应该写这个的,无奈公司昨天任务比较紧,所以没能按时 ...
- Xamarin.Android 使用 SimpleAdapter 打造 ListView 万能适配器
第一步:创建 layout1.axml 来展示列表详细内容 <?xml version="1.0" encoding="utf-8"?> <L ...
- Android之ListView性能优化——一行代码绑定数据——万能适配器
如下图,加入现在有一个这样的需求图,你会怎么做?作为一个初学者,之前我都是直接用SimpleAdapter结合一个Item的布局来实现的,感觉这样实现起来很方便(基本上一行代码就可以实现),而且也没有 ...
- Android万能适配器Adapter-android学习之旅(74)
万能适配器的代码的github地址是https://github.com/fengsehng/CommonAdapter 万能适配器的代码的github地址是https://github.com/fe ...
- 安卓开发笔记——打造万能适配器(Adapter)
为什么要打造万能适配器? 在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需 ...
- Android进阶笔记10:Android 万能适配器
1. Android 万能适配器 项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...
- Android开发之万能适配器
ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法 ...
- 打造android万能上拉下拉刷新框架——XRefreshView (二)
打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下 ...
- Android进阶笔记09:Android 万能适配器
1. Android 万能适配器 项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都 ...
随机推荐
- AndroidTips-052:.aar文件依赖
aar aar 文件是android 类库项目的输出文件,其中可以包含普通的.class,清单,以及android项目特有的资源文件. 使用方式 将.aar文件放在在自己项目的libs目录下 在gra ...
- static,你还敢用吗?(二)
为了压系统,昨天小组在测试环境模拟了一大批订单数据.今天上午查看记录的账单计息日志,发现了一大堆的MySqlException MySql.Data.MySqlClient.MySqlExceptio ...
- 在.Net中实现自己的简易AOP
RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...
- 【翻译】MongoDB指南/CRUD操作(四)
[原文地址]https://docs.mongodb.com/manual/ CRUD操作(四) 1 查询方案(Query Plans) MongoDB 查询优化程序处理查询并且针对给定可利用的索引选 ...
- 如何利用tcpdump对mysql进行抓包操作
命令如下: tcpdump -s -l -w - dst -i eno16777736 |strings 其中-i指定监听的网络接口,在RHEL 7下,网络接口名不再是之前的eth0,而是 eno16 ...
- 谈谈JS的观察者模式(自定义事件)
呼呼...前不久参加了一个笔试,里面有一到JS编程题,当时看着题目就蒙圈...后来研究了一下,原来就是所谓的观察者模式.就记下来...^_^ 题目 [附加题] 请实现下面的自定义事件 Event 对象 ...
- 以项目谈WebGIS中Web制图的设计和实现
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景介绍 一般WebGIS项目中,前端展示数据的流程基本是先做数据入 ...
- 洛谷P1547 Out of Hay
题目背景 奶牛爱干草 题目描述 Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发.农场之间总共有M (1 <= M <= 10,0 ...
- WiFi QC 自动测试:ixChariot API初探
Chariot虽然给我们提供了友好的界面,但是必须使用命令行或者使用它的API才能 实现自动测试.Chariot在安装的时候会让你选择命令行界面组件,在它的安装目录下面有一些工具, 暂时还不知道是干什 ...
- Linux.NET实战手记—自己动手改泥鳅(上)
各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...