basequickadapter使用 源码 报错 这怎么弄 我都没有改过

每次我都要写绕了很多圈子的convertView.setTag ,new ViewHolder。
可不可以直接通过一种方式让开发者只用写item数据与item布局中绑定的代码呢?
base-adapter-helper
& 是一个可以最大程度简化ListView adapter写法的库,它完全实现了我们期望的只写绑定代码的需求。
ListView lv = (ListView) findViewById(R.id.lv);
QuickAdapter&Blog& adapter = new QuickAdapter&Blog&(this, R.layout.item) {
protected void convert(BaseAdapterHelper helper, Blog blog) {
helper.setText(R.id.title, blog.getTitle());
helper.setText(R.id.author, blog.getAuthor());
helper.description(R.id.description, blog.getDescription());
helper.setImageUrl(R.id.litPic, blog.getLitPic());
adapter.addAll(bolgList);
lv.setAdapter(adapter);
new 一个QuickAdapter,重写convert()方法,再convert中使用helper的各种set方法完成数据的绑定。&注:helper是一个BaseAdapterHelper对象。
base-adapter-helper分析
通过研究&base-adapter-helper的代码,可以发现它:
base-adapter-helper有四个类:
BaseAdapterHelper
BaseQuickAdapter
EnhancedQuickAdapter
QuickAdapter
其中后三个都是adapter,第一个是帮助类。
虽然我们通常 使用的是QuickAdapter,但是QuickAdapter里面并没有做什么事情,要了解&base-adapter-helper,只需研究两个类就可以了
BaseAdapterHelper
BaseQuickAdapter
BaseQuickAdapter
BaseQuickAdapter完成了adapter的绝大部分操作。代码不多就全贴在这里了:
* Copyright 2013 Joan Zapata
* Licensed under the Apache License, Version 2.0 (the &License&);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an &AS IS& BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
package com.joanzapata.
import android.content.C
import android.view.G
import android.view.V
import android.view.ViewG
import android.widget.BaseA
import android.widget.FrameL
import android.widget.ProgressB
import java.util.ArrayL
import java.util.L
* Abstraction class of a BaseAdapter in which you only need
* to provide the convert() implementation.
* Using the provided BaseAdapterHelper, your code is minimalist.
* @param &T& The type of the items in the list.
public abstract class BaseQuickAdapter&T, H extends BaseAdapterHelper& extends BaseAdapter {
protected static final String TAG = BaseQuickAdapter.class.getSimpleName();
protected final C
protected final int layoutResId;
protected final List&T&
protected boolean displayIndeterminateProgress =
* Create a QuickAdapter.
* @param context
The context.
* @param layoutResId The layout resource id of each item.
public BaseQuickAdapter(Context context, int layoutResId) {
this(context, layoutResId, null);
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
* @param context
The context.
* @param layoutResId The layout resource id of each item.
* @param data
A new list is created out of this one to avoid mutable list
public BaseQuickAdapter(Context context, int layoutResId, List&T& data) {
this.data = data == null ? new ArrayList&T&() : new ArrayList&T&(data);
this.context =
this.layoutResId = layoutResId;
public int getCount() {
int extra = displayIndeterminateProgress ? 1 : 0;
return data.size() +
public T getItem(int position) {
if (position &= data.size())
return data.get(position);
public long getItemId(int position) {
public int getViewTypeCount() {
public int getItemViewType(int position) {
return position &= data.size() ? 1 : 0;
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 0) {
final H helper = getAdapterHelper(position, convertView, parent);
T item = getItem(position);
helper.setAssociatedObject(item);
convert(helper, item);
return helper.getView();
return createIndeterminateProgressView(convertView, parent);
private View createIndeterminateProgressView(View convertView, ViewGroup parent) {
if (convertView == null) {
FrameLayout container = new FrameLayout(context);
container.setForegroundGravity(Gravity.CENTER);
ProgressBar progress = new ProgressBar(context);
container.addView(progress);
convertView =
return convertV
public boolean isEnabled(int position) {
return position & data.size();
public void add(T elem) {
data.add(elem);
notifyDataSetChanged();
public void addAll(List&T& elem) {
data.addAll(elem);
notifyDataSetChanged();
public void set(T oldElem, T newElem) {
set(data.indexOf(oldElem), newElem);
public void set(int index, T elem) {
data.set(index, elem);
notifyDataSetChanged();
public void remove(T elem) {
data.remove(elem);
notifyDataSetChanged();
public void remove(int index) {
data.remove(index);
notifyDataSetChanged();
public void replaceAll(List&T& elem) {
data.clear();
data.addAll(elem);
notifyDataSetChanged();
public boolean contains(T elem) {
return data.contains(elem);
/** Clear data list */
public void clear() {
data.clear();
notifyDataSetChanged();
public void showIndeterminateProgress(boolean display) {
if (display == displayIndeterminateProgress)
displayIndeterminateProgress =
notifyDataSetChanged();
* Implement this method and use the helper to adapt the view to the given item.
* @param helper A fully initialized helper.
* @param item
The item that needs to be displayed.
protected abstract void convert(H helper, T item);
* You can override this method to use a custom BaseAdapterHelper in order to fit your needs
* @param position
The position of the item within the adapter's data set of the item whose view we want.
* @param convertView The old view to reuse, if possible. Note: You should check that this view
is non-null and of an appropriate type before using. If it is not possible to convert
this view to display the correct data, this method can create a new view.
Heterogeneous lists can specify their number of view types, so that this View is
always of the right type (see {@link #getViewTypeCount()} and
{@link #getItemViewType(int)}).
* @param parent
The parent that this view will eventually be attached to
* @return An instance of BaseAdapterHelper
protected abstract H getAdapterHelper(int position, View convertView, ViewGroup parent);
BaseQuickAdapter的成员变量只有四个:
protected final C
protected final int layoutResId;
protected final List&T&
protected boolean displayIndeterminateProgress =
其中context仅仅是为了获得某些控件需要的上下文,layoutResId为资源文件的id,如:R.layout.item。
最关键的则是data变量。
为了让adapter支持不同类型的list,它使用了泛型来定义:
protected final List&T&
接下来定义了一些adapter都会定义的方法,比如getCount,getView等,然后是一些帮助添加数据的方法,如add,addAll,set,remove等,其实这些方法对于我们研究简化adapter来说并没有什么用。
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 0) {
final H helper = getAdapterHelper(position, convertView, parent);
T item = getItem(position);
helper.setAssociatedObject(item);
convert(helper, item);
return helper.getView();
return createIndeterminateProgressView(convertView, parent);
在这个方法中,getItemViewType(position) == 0条件下执行的才是正常情况的代码,其余的情况是用于显示加载进度的。
首先,调用getAdapterHelper获得一个BaseAdapterHelper对象,
这个getAdapterHelper方法在本类中只是个抽象方法:
protected abstract H getAdapterHelper(int position, View convertView, ViewGroup parent);
具体的实现在QuickAdapter中,因为我们直接使用的其实是QuickAdapter,所以我们实际上调用的下面的代码:
protected BaseAdapterHelper getAdapterHelper(int position, View convertView, ViewGroup parent) {
return get(context, convertView, parent, layoutResId, position);
在这个方法中又调用了get方法,这个get方法是怎么定义的呢?这里很容易误解,认为他是QuickAdapter或者BaseAdapterHelper的成员方法,它其实是BaseAdapterHelper的一个静态方法,用ide的代码跳转功能就能看出来。为什么会这样,因为在这个类的import中:
import static com.joanzapata.android.BaseAdapterHelper.
直接引入一个类的静态方法(通常我们都是引入一个类),这中用法我还是第一次看到(少见多怪了哈)。
这个get方法是一个工厂方法,产生一个BaseAdapterHelper对象,有趣的是这个get方法的实现其实和ViewHolder模式中,产生ViewHolder的方式类似
static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new BaseAdapterHelper(context, parent, layoutId, position);
// Retrieve the existing helper and update its position
BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag();
existingHelper.position =
return existingH
判断convertView是否已经存在,不存在则新建一个BaseAdapterHelper对象,存在则直接从convertView的Tag中直接获取一个BaseAdapterHelper对象,所以说BaseAdapterHelper其实就是一个ViewHolder。
上面分析了getView中getAdapterHelper的流程(其实已经涉及到部分BaseAdapterHelper的代码),接下来是
T item = getItem(position);
helper.setAssociatedObject(item);
这两行代码用处不大。
下面关键的地方来了,convert方法
convert(helper, item);
它传入了helper和item两个参数。
convert方法是一个抽象方法。具体实现取决于BaseQuickAdapter的子类。
convert方法也是我们使用这个库时会直接操作的方法,在文章最开头我就用到了:
QuickAdapter&Blog& adapter = new QuickAdapter&Blog&(this, R.layout.item) {
protected void convert(BaseAdapterHelper helper, Blog blog) {
helper.setText(R.id.title, blog.getTitle());
helper.setText(R.id.author, blog.getAuthor());
helper.description(R.id.description, blog.getDescription());
helper.setImageUrl(R.id.litPic, blog.getLitPic());
它要完成的任务是数据的绑定工作。
convert方法调用之后,返回相应绑定完数据的view:
return helper.getView();
可见是通过helper的getView返回的。下面会讲到。
到这里BaseQuickAdapter的代码就基本分析完了。从上面的分析中,可以看到BaseAdapterHelper才是关键。
BaseAdapterHelper
就如上面提到的,BaseAdapterHelper的作用相当于ViewHolder。我们在分析getAdapterHelper部分也提到了BaseAdapterHelper的get方法,其实这个方法也是我们切入BaseAdapterHelper的入口。
我们再来看看这个get方法:
static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new BaseAdapterHelper(context, parent, layoutId, position);
// Retrieve the existing helper and update its position
BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag();
existingHelper.position =
return existingH
就如刚刚所说的“判断convertView是否已经存在,不存在则新建一个BaseAdapterHelper对象,存在则直接从convertView的Tag中直接获取一个BaseAdapterHelper对象”。
我们先看看第一个条件convertView == null
返回了一个新建的BaseAdapterHelper,那么我看看它的构造方法:
private BaseAdapterHelper(Context context, ViewGroup parent, int layoutId, int position) {
this.context =
this.position =
this.views = new SparseArray&View&();
convertView = LayoutInflater.from(context) //
.inflate(layoutId, parent, false);
convertView.setTag(this);
首先新建了一个view数组,SparseArray是稀疏数组,性能略高哈哈。这个数组是用于存放一个item中需要被绑定数据的view的(就是那些需要通过findviewByid获得的view)。
然后从item的布局文件中获得convertView,同时把this对象放到convertView的tag里,下次我们通过get方法获取BaseAdapterHelper对象的时候,就可以直接使用convertView.getTag()获取。
这里的convertView是一个成员变量,保存起来,然后在BaseQuickAdapter的getView中通过helper.getView()返回保存起来的convertView。
这里很绕是吧,其实说简单点那就是BaseAdapterHelper和convertView是相互持有的。
BaseAdapterHelper 构造方法中生成convertView 然后把持有它的BaseAdapterHelper放在自己的tag里,当convertView回收的时候,使用convertView.getTag()获得helper,然后再通过helper.getView()返回convertView给adapter的getView方法。
当然,在convertView能被回收的时候(convertView != null),其实可以不通过helper.getView()返回convertView,直接返回参数里的convertView也是可以的(实际上它们是同一个convertView)。
数据的绑定
数据的绑定是在convert方法中完成的。它本身是一个抽象方法,需要你在子类中写具体的实现,这样设计的好处就是它可以任意扩展,适应任何布局的adapter。一般来说一个抽象方法要想扩展,必须带一些非常实用的参数,
convert方法 中就有helper和item两个参数,我们来仔细看看这个方法的使用:
QuickAdapter&Blog& adapter = new QuickAdapter&Blog&(this, R.layout.item) {
protected void convert(BaseAdapterHelper helper, Blog blog) {
helper.setText(R.id.title, blog.getTitle());
helper.setText(R.id.author, blog.getAuthor());
helper.description(R.id.description, blog.getDescription());
helper.setImageUrl(R.id.litPic, blog.getLitPic());
adapter.addAll(bolgList);
item是数据,它来自于传入的blogList,helper是在BaseQuickAdapter的getView中实例化的,这里基本就是调用了helper的各种set方法,就拿setText方法为例:
public BaseAdapterHelper setText(int viewId, String value) {
TextView view = retrieveView(viewId);
view.setText(value);
看不出来啥,,倒是这个retrieveView有点意思
private &T extends View& T retrieveView(int viewId) {
View view = views.get(viewId);
if (view == null) {
view = convertView.findViewById(viewId);
views.put(viewId, view);
return (T)
}&pre name=&code& class=&java&&public BaseAdapterHelper setImageUrl(int viewId, String imageUrl) {
ImageView view = retrieveView(viewId);
Picasso.with(context).load(imageUrl).into(view);
首先,从views数组中寻找该id的view,没有找到,则用findviewById来找, 由于convertView是一个成员变量,因此在retrieveView中可以通过convertView找到相应id的view,一旦找到,我们就把它存在views中,这样能保证每个convertView只需调用一次findviewById。这点和普通ViewHolder的策略不太相同,普通ViewHolder,view是已知的,不是动态的,而我们的BaseAdapterHelper维护的view是动态数组,每find一次就保存起来。
另外retrieveView还有个很重要的特点,那就是他的返回值是用的泛型,这样,我们的的set方法就可以任意指定view的类型,比如上面的setText方法中,最后转换成的是TextView类型。retrieveView的实现也是我觉得这个库设计巧妙的一大原因。
实际上,我以前也尝试过要实现一个通用的ViewHolder,我的思路也是想办法能动态的往ViewHolder中增加变量,注意我想到的仅仅是动态的增加变量,而且显然是不能实现的,而base-adapter-helper
不增加变量,转而维护一个可以任意扩展的views数组,虽然views中都是普通的view,但是这些view随时都可以转换。想到这里,突然感觉这里即便没有使用泛型貌似也不会影响灵活性。
base-adapter-helper的缺点
实际上,上面的代码缺乏一定的灵活性,那就是绑定数据我们都是通过helper的set方法实现的,在上面的代码中我们使用到了两个set方法setText和setImageUrl
让我们看看它是如何定义的:
public BaseAdapterHelper setText(int viewId, String value) {
TextView view = retrieveView(viewId);
view.setText(value);
setImageUrl
public BaseAdapterHelper setImageUrl(int viewId, String imageUrl) {
ImageView view = retrieveView(viewId);
Picasso.with(context).load(imageUrl).into(view);
要是我们需要设置一个View的透明度呢?幸好BaseAdapterHelper也定义了相关的方法:
public BaseAdapterHelper setAlpha(int viewId, float value) {
if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.HONEYCOMB) {
retrieveView(viewId).setAlpha(value);
// Pre-honeycomb hack to set Alpha value
AlphaAnimation alpha = new AlphaAnimation(value, value);
alpha.setDuration(0);
alpha.setFillAfter(true);
retrieveView(viewId).startAnimation(alpha);
但是我们知道,理论上你永远无法在BaseAdapterHelper中实现完所有我们对view的设定需求。而且从setImageUrl方法中你可以看到,它是通过Picasso来加载图片的,要是我们想用Glide来加载呢?似乎得修改BaseAdapterHelper的源码了。
我可以在BaseAdapterHelper中增加一个叫setImageUrlGlide的方法,然后用Glide来实现图片的加载,但是如果我们又想用Fresco来加载呢,再增加一个吗?显然这是无穷无尽的。
其实从一开始我就觉得采用定义set方法来设置数据的方式是不靠谱的。
于是我这样做:
QuickAdapter&Blog& adapter = new QuickAdapter&Blog&(this, R.layout.item) {
protected void convert(BaseAdapterHelper helper, Blog blog) {
TextView titleView = helper.retrieveView(R.id.title);
titleView.setText(blog.getTitle());
TextView authorView = helper.retrieveView(R.id.author);
authorView.setText(blog.getAuthor());
TextView descriptionView = helper.retrieveView(R.id.description);
descriptionView.setText(blog.getDescription());
ImageView image= helper.retrieveView(R.id.litPic);
//如何显示图片就取决于你自己了
我们直接跳过了set方法,直接通过retrieveView获得view的实例,但是retrieveView是私有方法,我们需要把它改成public的才能这样做。
这样,我们虽然多了一些代码,但是整个adapter的实现我们仍然全部是在convert中完成的,并没有增加任何其他关联的代码。
更正:其实这个库也提供了一个getView方法:
public &T extends View& T getView(int viewId) {
return retrieveView(viewId);
所以我们不需要把retrieveView改成public,直接使用getView方法:
QuickAdapter&Blog& adapter = new QuickAdapter&Blog&(this, R.layout.item) {
protected void convert(BaseAdapterHelper helper, Blog blog) {
TextView titleView = helper.getView(R.id.title);
titleView.setText(blog.getTitle());
TextView authorView = helper.getView(R.id.author);
authorView.setText(blog.getAuthor());
TextView descriptionView = helper.getView(R.id.description);
descriptionView.setText(blog.getDescription());
ImageView image= helper.getView(R.id.litPic);
//如何显示图片就取决于你自己了
base-adapter-helper的分析就此结束,其实理解之后,感觉核心的东西很少,但是为什么我就没有实现呢?拦住我的其实也就是那么一点点技巧而已,哈哈。
总的说来,核心的东西只有三点:
我比较喜欢这个库的调用方式,所以决定尝试看看是否可以用同样的api实现对RecyclerView 适配器的简化。成功了我会告诉大家。
已经写好了:
此文转自:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1168次
排名:千里之外
(1)(1)(1)(3)(1)(1)BaseAdapterHelper 源码分析【用户高赞】
BaseAdapterHelper 源码分析【用户高赞】
作者:呆萌小七
资源类型:
运行环境:
此内容为用户分享的优质Android内容,主要是BaseAdapterHelper 源码。1. 功能介绍1.1. base-adapter-helperbase-adapter-helper 是对传统的 BaseAdapter ViewHolder 模式的一个封装。主要功能就是简化我们书写 AbsListView 的 Adapter 的代码,如 ListView,GridView。1.2 基本使用mListView.setAdapter(mAdapter = new QuickAdapter&Bean&(MainActivity.this, R.layout.item_list, mDatas) {
protected void convert(BaseAdapterHelper helper, Bean item) {
helper.setText(R.id.tv_title, item.getTitle());
helper.setImageUrl(R.id.id_icon, item.getUrl());
helper.setText(R.id.tv_describe, item.getDesc());
helper.setText(R.id.tv_phone, item.getPhone());
helper.setText(R.id.tv_time, item.getTime());
1.3 优点(1) 提供 QucikAdapter,省去类似 getCount() 等抽象函数的书写,只需关注 Model 到 View 的显示。(2) BaseAdapterHelper 中封装了大量用于为 View 操作的辅助方法,例如从网络加载图片:helper.setImageUrl(R.id.iv_photo, item.getPhotoUrl());1.4 缺点(1) 与 Picasso 耦合,想替换为其他图片缓存需要修改源码。可通过接口方式,供三方根据自己的图片缓存库实现图片获取,或者直接去掉helper.setImageUrl(…)函数。(2) 与内部添加的进度条偶尔,导致不支持多种类型布局在本文最后给出不改动进度条的解决方法。更好的实现方式应该是通过接口方式暴露,供三方自己设置。(3) 目前的方案也不支持HeaderViewListAdapter。总体来说这个库比较简单,实现也有待改进。具体的内容可以下载附件来看,。
服务热线:400-678-8266BaseAdapterHelper详解源码分析,让你摆脱狂写一堆Adapter烦恼(二十五) - [ FastDev4Android ] - 看云
(一).前言:
Base-Adater-Helper是对我们传统的BaseAdapter的ViewHolder的模式的一个抽象封装,主要的功能可以让我们简化的书写AbsListView,例如ListView,GridView的自定义Adapter的代码,上一篇我们已经对该项目的基本使用做了介绍实例,今天我们来对该项目的实现详解源码分析一下,同时我们可以对此框架进行扩展开发。
FastDev4Android框架项目地址:
基本使用方式如下:
我们看一下它的实例使用方法:
mAdapter = newQuickAdapter&ModuleBean&(this, R.layout.lv_item_base_layout,moduleBeans){
protected voidconvert(BaseAdapterHelper helper, ModuleBean item) {
//列表底下显示进度
mAdapter.showIndeterminateProgress(true);
helper.setText(R.id.text_lv_item_title, item.getModulename())
.setText(R.id.text_lv_item_description, item.getDescription())
.setImageUrl(R.id.img_lv_item, item.getImgurl());
lv_base_adapter.setAdapter(mAdapter);
(二).总体分析:
整个项目其实比较简单也就是四个主要的类:
BaseAdapterHelper
BaseQuickAdapter
EnhancedQuickAdapter
QuickAdapter
通过阅读整个项目源代码之后发现,当前实现也是基于ViewHolder模式的,等会我
们分析就知道了。其中view类型相关的采用泛型存储,最重要的数据绑定工作,采用抽象函数convert()实现,全部交给用户来实现自定义的绑定。
从上面的基本使用中发现,我们在使用该base-adapter-helper过程中,只需要创建newQuickAdapter()传入布局,数据,控件和数据模型绑定即可。但是我们查看QuickAdapter类的代码发现:
packagecom.chinaztt.fda.adapter.
importandroid.content.C
importandroid.view.V
importandroid.view.ViewG
importjava.util.L
import staticcom.chinaztt.fda.adapter.base.BaseAdapterHelper.
* Abstraction class of a BaseAdapter in whichyou only need
* to provide the convert()implementation.&br/&
* Using the provided BaseAdapterHelper, yourcode is minimalist.
* @param &T& The type of the items inthe list.
public abstractclass QuickAdapter&T& extends BaseQuickAdapter&T,BaseAdapterHelper& {
* Create a QuickAdapter.
* @param context
The context.
* @param layoutResId The layout resourceid of each item.
public QuickAdapter(Context context, intlayoutResId) {
super(context, layoutResId);
* Same asQuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
* @param context
The context.
* @param layoutResId The layout resourceid of each item.
* @param data
A new list is created out of this oneto avoid mutable list
public QuickAdapter(Context context, intlayoutResId, List&T& data) {
super(context, layoutResId, data);
* 进行获取类ViewHolder的
BaseAdapterHelper
* @param position
The position of the item within theadapter's data set of the item whose view we want.
* @param convertView The old view toreuse, if possible. Note: You should check that this view
is non-null and of anappropriate type before using. If it is not possible to convert
this view to display thecorrect data, this method can create a new view.
Heterogeneous lists canspecify their number of view types, so that this View is
always of the right type(see {@link #getViewTypeCount()} and
{@link#getItemViewType(int)}).
* @param parent
The parent that this view will eventuallybe attached to
protected BaseAdapterHelpergetAdapterHelper(int position, View convertView, ViewGroup parent) {
return get(context, convertView,parent, layoutResId, position);
其实它并没有做什么其他更多的时候,就只有两个构造方法,和一个获取BaseAdapterHelper对象的方法。所以要研究该框架,我们只需要研究它的父类BaseQuickAdapter和BaseAdapterHelper类即可。最后简单的看一下EnhancedQuickAdapter类。
2.1.BaseQuickAdapter类:该类继承了BaseAdapter类,同时实现了BaseAdapter中通用的几个抽象方法(也就是我们平时自定义Adapter需要实现的几个方法),完成了Adapter要做的绝大多数操作以及对于Data操作的方法(不过个人赶脚用处不是特别大哈~个人见解)。该类还有两个泛型数据,其中T代表数据,H针对BaseAdapterHelper。
packagecom.chinaztt.fda.adapter.
importandroid.content.C
importandroid.view.G
importandroid.view.V
importandroid.view.ViewG
importandroid.widget.BaseA
importandroid.widget.FrameL
importandroid.widget.ProgressB
importjava.util.ArrayL
importjava.util.L
* Abstraction class of a BaseAdapter in whichyou only need
* to provide the convert()implementation.&br/&
* Using the provided BaseAdapterHelper, yourcode is minimalist.
* @param &T& The type of the items inthe list.
public abstractclass BaseQuickAdapter&T, H extends BaseAdapterHelper& extendsBaseAdapter {
protected static final String TAG =BaseQuickAdapter.class.getSimpleName();
//上下文引用
protected final C
//需要显示的布局id
protected final int layoutResId;
//需要显示的数据
protected final List&T&
//是否显示进度
protected booleandisplayIndeterminateProgress =
* Create a QuickAdapter.
* @param context
The context.
* @param layoutResId The layout resourceid of each item.
public BaseQuickAdapter(Context context,int layoutResId) {
this(context, layoutResId, null);
* Same asQuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
* @param context
The context.
* @param layoutResId The layout resourceid of each item.
* @param data
A new list is created out of this oneto avoid mutable list
public BaseQuickAdapter(Context context,int layoutResId, List&T& data) {
this.data = data == null ? newArrayList&T&() : new ArrayList&T&(data);
this.context =
this.layoutResId = layoutResId;
* 判断是否需要显示进度,如果显示 数量+1
public int getCount() {
int extra =displayIndeterminateProgress ? 1 : 0;
return data.size() +
* 判断索引是否大于等于数据长度,如果等于,最后一个item应该为进度,那么返回的数据对象为null即可
* @param position
public T getItem(int position) {
if (position &= data.size())
return data.get(position);
public long getItemId(int position) {
* view类型返回2,这边还需要显示进度bar
public int getViewTypeCount() {
* 进行判断索引是不是已经大于等于数据的长度
* 如果超过或者等于数据的长度 返回1
* @param position
public int getItemViewType(int position) {
return position &= data.size() ? 1 :0;
public View getView(int position, ViewconvertView, ViewGroup parent) {
if (getItemViewType(position) == 0) {
//获取适配器helper --相当于获取ViewHolder-BaseAdapterHelper
final H helper =getAdapterHelper(position, convertView, parent);
//获取item model 数据
T item = getItem(position);
//给子类QuickAdapter来进行实现,不过QuickAdapter也是抽象类,给具体创建的类进行实现
convert(helper, item);
helper.setAssociatedObject(item);
return helper.getView();
//显示进度
returncreateIndeterminateProgressView(convertView, parent);
* 创建进度条 显示在view的结尾
* @param convertView
* @param parent
private ViewcreateIndeterminateProgressView(View convertView, ViewGroup parent) {
if (convertView == null) {
FrameLayout container = newFrameLayout(context);
container.setForegroundGravity(Gravity.CENTER);
ProgressBar progress = newProgressBar(context);
container.addView(progress);
convertView =
return convertV
public boolean isEnabled(int position) {
return position & data.size();
//====================================================
//下面的方法基本封装了操作集合相关的
//主要为新增add,设置set,移除remove以及替换,是否存在判断
//=====================================================
public void add(T elem) {
data.add(elem);
notifyDataSetChanged();
public void addAll(List&T& elem) {
data.addAll(elem);
notifyDataSetChanged();
public void set(T oldElem, T newElem) {
set(data.indexOf(oldElem), newElem);
public void set(int index, T elem) {
data.set(index, elem);
notifyDataSetChanged();
public void remove(T elem) {
data.remove(elem);
notifyDataSetChanged();
public void remove(int index) {
data.remove(index);
notifyDataSetChanged();
public void replaceAll(List&T& elem){
data.clear();
data.addAll(elem);
notifyDataSetChanged();
public boolean contains(T elem) {
return data.contains(elem);
* 清空数组
/** Clear data list */
public void clear() {
data.clear();
notifyDataSetChanged();
public voidshowIndeterminateProgress(boolean display) {
if (display ==displayIndeterminateProgress)
displayIndeterminateProgress =
notifyDataSetChanged();
* 实现该方法,让用户自己绑定控件和数据
* Implement this method and use the helperto adapt the view to the given item.
* @param helper A fully initializedhelper.
* @param item
The item that needs to be displayed.
protected abstract void convert(H helper, Titem);
* You can override this method to use acustom BaseAdapterHelper in order to fit your needs
* @param position
The position of the item within theadapter's data set of the item whose view we want.
* @param convertView The old view toreuse, if possible. Note: You should check that this view
is non-null and of anappropriate type before using. If it is not possible to convert
this view to display thecorrect data, this method can create a new view.
Heterogeneous lists canspecify their number of view types, so that this View is
always of the right type(see {@link #getViewTypeCount()} and
{@link#getItemViewType(int)}).
* @param parent
The parent that this view will eventuallybe attached to
* @return An instance of BaseAdapterHelper
protected abstract H getAdapterHelper(intposition, View convertView, ViewGroup parent);
重点我们来看下这个类的相关实现:
2.1.1.成员变量context为获取控件所需要的上下文,layoutResId为布局文件的id。其中data的类型是List的,由于这边传入的实体信息可能是不同类型的集合,所以这边采用了泛型来进行定义了。
2.1.2.getViewTypeCount(),getItemViewType()这边我们可以看源代码第一个函数返回2,第二个函数会进行判断返回position。因为base-adapter-helper已经实现的progressbar进度的显示控制条。
2.1.3.然后是一些实现adapter都要实现的方法例如:getCount,getView,getItem,getItemId之类的方法,还有一些关于数据操作的方法。
2.1.4.重点看一下getView方法:
public ViewgetView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == 0) {
//获取适配器helper --相当于获取ViewHolder-BaseAdapterHelper
final H helper =getAdapterHelper(position, convertView, parent);
//获取item model 数据
T item = getItem(position);
//给子类QuickAdapter来进行实现,不过QuickAdapter也是抽象类,给具体创建的类进行实现
convert(helper, item);
helper.setAssociatedObject(item);
return helper.getView();
//显示进度
returncreateIndeterminateProgressView(convertView, parent);
重点地方已经注释了,在这个方法中,会首先进行判断getItemViewType(position)的值,如果返回值不等于0的时候,那就是说显示底部的进度,其他的情况会正常加载view。此时通过抽象方法getAdapterHelper()来进行获取一个BaseAdapterHelper。
该抽象方法的实现类是QuickAdapter:
* 进行获取类ViewHolder的
BaseAdapterHelper
* @param position
The position of the item within theadapter's data set of the item whose view we want.
* @param convertView The old view toreuse, if possible. Note: You should check that this view
is non-null and of anappropriate type before using. If it is not possible to convert
this view to display thecorrect data, this method can create a new view.
Heterogeneous lists canspecify their number of view types, so that this View is
always of the right type(see {@link #getViewTypeCount()} and
{@link#getItemViewType(int)}).
* @param parent
The parent that this view will eventuallybe attached to
protected BaseAdapterHelpergetAdapterHelper(int position, View convertView, ViewGroup parent) {
return get(context, convertView,parent, layoutResId, position);
其中又去调用BaseAdapterHelper的如下方法:
/** This method ispackage private and should only be used by QuickAdapter. */
* 进行获取类ViewHolder的BaseAdapterHelper对象
* @param context
上下文引用
* @param convertView
* @param parent
父控件view
* @param layoutId
* @param position
static BaseAdapterHelper get(Contextcontext, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return newBaseAdapterHelper(context, parent, layoutId, position);
// Retrieve the existing helper andupdate its position
BaseAdapterHelper existingHelper =(BaseAdapterHelper) convertView.getTag();
existingHelper.position =
return existingH
该类中的实现方法就是首先判断convertView是否为null,如果为null,进行创建。否则直接从getTag()进行获取,然后返回当前BaseAdapterHelper,到这边相比大家有没有明白BaseAdapterHelper和我们以前接触的ViewHolder相似了呢?对的,这边的BaseAdapterHelper其实就是充当的ViewHolder角色。
上面我们分析了getAdapterHelper的生成方式,下面我们看一下itemdata的获取,这个比较简单直接如下即可:
//获取item model数据
T item = getItem(position);
该类最后我们来看一个最关键的代码
//给子类QuickAdapter来进行实现,不过QuickAdapter也是抽象类,给具体创建的类进行实现
convert(helper, item);
该convert()为抽象方法,convert的参数为BaseAdapterHelper和实体对象item,让我们用户可以自定义自由绑定数据到控件中。绑定成功之后直接通过调用helper.getView()返回即可。
2.2.BaseAdapterHelper类
上面get()方法的时候已经说过BaseAdapterHelper相当于ViewHolder,同时该类还提供一大堆的方法来让我们进行设置view的数据,属性,以及一些事件方法。 我们首先开看构造方法:
protectedBaseAdapterHelper(Context context, ViewGroup parent, int layoutId, intposition) {
this.context =
this.position =
this.views = newSparseArray&View&();
convertView =LayoutInflater.from(context) //根据布局id来加载view
.inflate(layoutId, parent,false);
convertView.setTag(this);//相当于存放ViewHolder
该构造方法创建一个稀疏数组来存放view对象(用来绑定数据的)。然后根据布局id来进行获取convertView,同时把当前对象加入到convertView得tag中,然后后面我们可以通过convertView.getTag()来进行获取,这样保持BaseAdapterHelper对于convertView的相互持有引用。
除了以上的构造方法以外,还有另外一个进入BaseAdapterHelper的入口:
* This method is the only entry point toget a BaseAdapterHelper.
* @param context
The current context.
* @param convertView The convertView argpassed to the getView() method.
* @param parent
The parent arg passed to the getView()method.
* @return A BaseAdapterHelper instance.
public static BaseAdapterHelper get(Contextcontext, View convertView, ViewGroup parent, int layoutId) {
return get(context, convertView,parent, layoutId, -1);
/** This method is package private andshould only be used by QuickAdapter. */
* 进行获取类ViewHolder的BaseAdapterHelper对象
* @param context
上下文引用
* @param convertView
* @param parent
父控件view
* @param layoutId
* @param position
static BaseAdapterHelper get(Contextcontext, View convertView, ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return newBaseAdapterHelper(context, parent, layoutId, position);
// Retrieve the existing helper andupdate its position
BaseAdapterHelper existingHelper =(BaseAdapterHelper) convertView.getTag();
existingHelper.position =
return existingH
上面会进行判断convertView是否存在,不存在进行调用构造方法创建,存在直接从convertView.getTag()来获取BaseAdapterHelper对象。
下面我们来另外的比较重要的两个方法,主要是获取view控件,然后同时加入到稀疏数组中:
public &T extends View& T getView(intviewId) {
return retrieveView(viewId);
* 进行从模板view中获取相应的控件 然后放入到view控件集合中
protected &T extends View& TretrieveView(int viewId) {
//从集合中获取当前viewId的view,如果集合中不存在,那么从view重findById()
//获取出来存放到集合中 并且返回
View view = views.get(viewId);
if (view == null) {
view =convertView.findViewById(viewId);
views.put(viewId, view);
return (T)
上面方法我们可以看出,每次调用retrieveView方法的时候,都会根据viewId去views集合中查询一下,如果不存在,那么会通过findViewById(viewId)来进行获取,同时把该view加入到集合中,这样下次查询就不需要重复调用findViewById()了。
其他一些工具方法,例如设置字体,文本,图片,颜色,事件啊等等….
一大堆的方法这边就不贴代码了,具体每个方法的含义已经在项目源代码中注释了,大家有兴趣可以去下载项目然后去阅读一下:
FastDev4Android框架项目地址:
2.3.EnhancedQuickAdapter类:该类是继承自QuickAdapter,其他多出下面的两个方法:
* 进行绑定控件和数据
数据发生变化
* @param helper A fully initializedhelper.
* @param item
The item that needs to be displayed.
protected final voidconvert(BaseAdapterHelper helper, T item) {
boolean itemChanged =helper.associatedObject == null || !helper.associatedObject.equals(item);
helper.associatedObject =
convert(helper, item, itemChanged);
* 让用户来自定义
* @param helper
The helper to use to adapt the view.
* @param item
The item you should adapt the view to.
* @param itemChanged Whether or not thehelper was bound to another object before.
protected abstract voidconvert(BaseAdapterHelper helper, T item, boolean itemChanged);
仔细看convert()方法,多了第三方参数itemChanged,对于data集合发生改变的时候刷新View。
(三).改进点:
我们在进行控件,数据模型进行绑定的时候都是采用set方法才完成。但是我们的需求是千变万化的,就拿图片加载来说,框架内部默认是采用Picasso来加载图片的。但是如果我们的项目想要采用Volley,UIL或者Fresco呢?那么我们不得不需要在里边进行扩展相应的方法来实现了。虽然这种方案可以解决问题,但是如果还有其他方案,那么一直在扩展就会变得很庞大了。幸运的时候convert()方法回调回来的BaseAdapterHelper对象helper,该类中有getView()和retrieveView()方法,同时getView()还是public,对外开放的,我们在convert()实现方法中直接通过getView()即可获取view,然后如何显示图片就看我们自己的了。除此之外里边很多设置字体,文本等等很少辅助类,如果需要设置更多的东西,我们需要不断的扩展。
(四).结束语:
经过昨天和今天的讲解介绍,相应大家对于base-adapter-helper的基本使用和源码原理分析有一个比较清晰的了解,以后在项目中也可以多多使用这个,一定会提高写代码的效率。其他这个框架学习分析下来,非常核心的东西也还是比较好理解,重点要看思考,分析吧。继续加油。
到此Base-Adapter-Helper的基本介绍和基本使用已经讲完了,具体实例和框架注释过的全部代码已经上传到FastDev4Android项目中了。
同时欢迎大家去Github站点进行clone或者下载浏览:
同时欢迎大家star和fork整个开源快速开发框架项目~
页面正在加载中

我要回帖

更多关于 baseadapter的用法 的文章

 

随机推荐