BaseAdapter是应用最多的一种适配了。它是一个抽象类,需要重写方法完成自定义适配器的功能,这就比较自由灵活,能实现各种想要的效果。

之前讲到的SimpleAdapterArrayAdapter 就是它的子类。

下面介绍如何使用BaseAdapter实现自定义适配器。

基础知识点

使用BaseAdapter,只需继承它并实现下面4个方法即可:

public int getCount() //item的数目,即适配器要显示的数据项个数
public Object getItem(int position) //获取指定位置的数据项
public long getItemId(int position) //获取指定位置的数据项id
public View getView(int position, View convertView, ViewGroup parent) //获取每一项显示内容-view

下面通过简单示例,详细讲解BaseAdapter的使用以及注意事项

示例讲解

这次示例使用GridView作为显示组件。

布局文件,仅一个GridView的组件:base_adapter_act.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<GridView
android:id="@+id/base_adapter_lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>

文本资源,适配器填充的数据。和SimpleAdapter一样的:

<array name="anime_name">
<item>海贼王</item>
<item>进击的巨人</item>
<item>火影忍者</item>
<item>斩赤红之瞳</item>
<item>秦时明月</item>
<item>西游记</item>
<item>葫芦娃</item>
</array> <array name="anime_author">
<item>尾田荣一郎</item>
<item>谏山创</item>
<item>岸本齐史</item>
<item>タカヒロ</item>
<item>玄机科技</item>
<item>央视</item>
<item>上海美术电影</item>
</array>

每一项的布局文件:base_adapter_grid_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView android:id="@+id/anime_cover_img"
android:layout_width="match_parent"
android:layout_margin="1dp"
android:layout_height="100dp"
android:scaleType="fitXY"/> <LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:orientation="vertical"
android:layout_below="@id/anime_cover_img">
<TextView
android:id="@+id/anime_name_txt"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:textStyle="bold"
android:textSize="15sp"
android:layout_weight="3"/> <TextView android:id="@+id/anime_author_txt"
android:layout_width="match_parent"
android:layout_height="0dp"
android:gravity="center"
android:textStyle="italic"
android:layout_weight="2"
android:textSize="10sp"/> <View
android:layout_width="match_parent"
android:layout_height="3dp" />
</LinearLayout>
</RelativeLayout>

常识1:android:layout_weight分配的大小=(父控件大小-android:layout_width)*权重比例大小

如果android:layout_width的大小已经达到或超过父控件的大小,则android:layout_weight是会失效的。

BaseAdapterActivity.java, 适配器的使用,代码如下

package com.flx.adaptertest.baseadapter;

import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.SimpleAdapter; import com.flx.adaptertest.R; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class BaseAdapterActivity extends Activity {
private static final String TAG = "BaseAdapterActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState );
setContentView( R.layout.base_adapter_act );
GridView gridView = findViewById(R.id.base_adapter_lv);
gridView.setNumColumns(2);
gridView.setOnItemClickListener( new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d( TAG, "onItemClick: position="+ position + ";text=" + parent.getAdapter().getItem(position).toString());
}
} ); List<AnimeBean> animeBeans = new ArrayList<>();
Resources resources = this.getResources();
String[] anime_names = resources.getStringArray( R.array.anime_name );
String[] anime_authors = resources.getStringArray( R.array.anime_author );
int[] coverImgs = {R.drawable.hzw1, R.drawable.jjdjr1, R.drawable.hyrz1,
R.drawable.zchzt1, R.drawable.qsmy1, R.drawable.xyj1, R.drawable.hlw1};
for (int i = 0; i < anime_names.length; i++) {
animeBeans.add(new AnimeBean(anime_names[i], anime_authors[i], coverImgs[i]));
}
gridView.setAdapter( new AnimeAdapter(this, animeBeans) );
}
}

这里创建了两个类,AnimeBean和AnimeAdapter。

AnimeBean是一个java bean类,数据以Bean类组织,其中主要是Getter和Setter的方法。适配器显示的每一项数据在一个AnimeBean对象中。

AnimeAdapter是继承BaseAdapter的自定义的适配器类,实现了上述讲到的4个方法。

AnimeBean.java

package com.flx.adaptertest.baseadapter;

import android.support.annotation.NonNull;

public class AnimeBean {
private String mAnimeName;
private String mAnimeAuthor;
private int mAnimeCoverImg; public AnimeBean(String animeName, String animeAuthor, int animeCoverImg) {
this.mAnimeName = animeName;
this.mAnimeAuthor = animeAuthor;
this.mAnimeCoverImg = animeCoverImg;
} public String getmAnimeName() {
return this.mAnimeName;
} public void setmAnimeName(String animeName) {
this.mAnimeName = animeName;
} public String getmAnimeAuthor() {
return this.mAnimeAuthor;
} public void setmAnimeAuthor(String animeAuthor) {
this.mAnimeAuthor = animeAuthor;
} public int getmAnimeCoverImg() {
return this.mAnimeCoverImg;
} public void setmAnimeCoverImg(int animeCoverImg) {
this.mAnimeCoverImg = animeCoverImg;
} @NonNull
@Override
public String toString() {
return "mAnimeName:"+mAnimeName+";mAnimeAuthor:"+mAnimeAuthor+";mAnimeCoverImg:"+mAnimeCoverImg;
}
}

最后一个toString用户打印Bean里面数据的内容,在BaseAdapterActivity的适配器点击项监听处有调用。

AnimeAdapter.java

package com.flx.adaptertest.baseadapter;

import android.content.Context;
import android.util.Log;
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 com.flx.adaptertest.R;
import java.util.List; public class AnimeAdapter extends BaseAdapter {
private static final String TAG = "AnimeAdapter";
private LayoutInflater mLayoutInflater;//布局加载器对象
private List<AnimeBean> mAnimeBeans;//数据源 //构造方法,包含了数据源和上下文。将数据和适配器关联起来了。
public AnimeAdapter(Context context, List<AnimeBean> animeBeans) {
mLayoutInflater = LayoutInflater.from(context);
mAnimeBeans = animeBeans;
} //item的数目,即适配器要显示的数据项个数
@Override
public int getCount() {
return mAnimeBeans != null ? mAnimeBeans.size() : 0;
} //获取指定位置的数据项
@Override
public Object getItem(int position) {
return mAnimeBeans != null ? mAnimeBeans.get(position) : null;
} //获取指定位置的数据项id
@Override
public long getItemId(int position) {
return position;
} //获取每一项显示内容-view
/**
*方法3:
* 这种方法改进了方法1和方法2的弊端,避免了每次都创建新的View对象和通过findViewById查找组件 而造成的耗时 耗资源的问题。
* 创建View对象通过判空避免了:if (convertView == null)
* findViewById()通过ViewHolder缓存下来了,通过setTag设置到View了,需要时可以直接获取到。
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
//convertView是显示项的视图。为null时即表示未被实例化过,GridView缓存池中没有缓存
Log.d( TAG, "getView: position=" + position +";convertView="+convertView );
if (convertView == null) {
convertView = mLayoutInflater.inflate( R.layout.base_adapter_grid_item, null );
//创建ViewHolder对象,并赋值
viewHolder = new ViewHolder();
viewHolder.animeNameTxt = convertView.findViewById(R.id.anime_name_txt);
viewHolder.animeAuthorTxt = convertView.findViewById(R.id.anime_author_txt);
viewHolder.animeCoverImg = convertView.findViewById(R.id.anime_cover_img);
//通过setTag,设置与convertView关联的标签ViewHolder,将convertView与ViewHolder关联
convertView.setTag(viewHolder);
} else {
//从缓存中返回convertView设置的标签:ViewHolder
viewHolder = (ViewHolder) convertView.getTag();
} AnimeBean animeBean = mAnimeBeans.get(position);
viewHolder.animeNameTxt.setText(animeBean.getmAnimeName());
viewHolder.animeAuthorTxt.setText(animeBean.getmAnimeAuthor());
viewHolder.animeCoverImg.setImageResource(animeBean.getmAnimeCoverImg());
return convertView;
} //缓存控件
private class ViewHolder {
public TextView animeNameTxt;
public TextView animeAuthorTxt;
public ImageView animeCoverImg;
} /**
* 方法1:
* 这种方法的弊端在于:很明显,每次都会创建新的convertView对象,并通过findViewById查找对应组件。
* 当数据项很大且比较复杂时问题很明显,耗时 耗资源
* 没有使用GridView ListView的缓存机制。
*/
/* @Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mLayoutInflater.inflate( R.layout.base_adapter_grid_item, null );
TextView animeNameTxt = convertView.findViewById(R.id.anime_name_txt);
TextView animeAuthorTxt = convertView.findViewById(R.id.anime_author_txt);
ImageView animeCoverImg = convertView.findViewById(R.id.anime_cover_img); AnimeBean animeBean = mAnimeBeans.get(position);
animeNameTxt.setText(animeBean.getmAnimeName());
animeAuthorTxt.setText(animeBean.getmAnimeAuthor());
animeCoverImg.setImageResource(animeBean.getmAnimeCoverImg());
return convertView;
}*/ /**
* 方法2:
* 该方法时方法1的改进,使用了缓存机制。
* 这种方法的弊端在于:每次都会通过findViewById()去遍历视图树,当布局很复杂时就会很耗时
*/
/*@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mLayoutInflater.inflate( R.layout.base_adapter_grid_item, null );
}
TextView animeNameTxt = convertView.findViewById(R.id.anime_name_txt);
TextView animeAuthorTxt = convertView.findViewById(R.id.anime_author_txt);
ImageView animeCoverImg = convertView.findViewById(R.id.anime_cover_img); AnimeBean animeBean = mAnimeBeans.get(position);
animeNameTxt.setText(animeBean.getmAnimeName());
animeAuthorTxt.setText(animeBean.getmAnimeAuthor());
animeCoverImg.setImageResource(animeBean.getmAnimeCoverImg());
return convertView;
}*/ }

代码中注释做了详细说明,需要注意几点:

1.自定义的Adapter继承了BaseAdapter,需要实现最初讲到的4个方法。getCount()、getItem()、getItemId()都比较简单,注意getView()的实现。

2.GridView、ListView等是由缓存机制的,当需要显示的时候才会显示,不需要显示的时候在缓存池中。当要显示的信息过多,超过屏幕很多,滑出的信息和滑入的信息 都是从缓存池中获取的,缓存池中的信息不会创建所有或马上销毁。(最后部分有将数据调整为1000后 也能看出这一点)

3.上述代码中,getView()列出了3种方法,方法1、方法2有各自明显缺陷,方法3是一个比较好的方法很好的避免了每次都创建新的View对象和通过findViewById查找组件 而造成的耗时 耗资源的问题。具体请看上述代码和注释。

示例效果

下面是效果图

点击其中一项,log如下:

2019-11-27 14:36:33.949 4655-4655/? D/BaseAdapterActivity: onItemClick:
position=0;text=mAnimeName:海贼王;mAnimeAuthor:尾田荣一郎;mAnimeCoverImg:2131165272

要看下getView() 方法3的效果,可以将数据调整为1000组,可以在BaseAdapterActivity中做如下修改

//        for (int i = 0; i < anime_names.length; i++) {
// animeBeans.add(new AnimeBean(anime_names[i], anime_authors[i], coverImgs[i]));
// }
for (int i = 0; i < 1000; i++) {
int ii = i%anime_names.length;
animeBeans.add(new AnimeBean(anime_names[ii], anime_authors[ii], coverImgs[ii]));
}

后面大部分View是没有创建的,向下滑动 才会逐步创建,如下的log,

滑动逐步显示后面的信息,后面信息都不需要每次创建View而是通过viewHolder = (ViewHolder) convertView.getTag()从缓存中获取来的,然后填充数据即可。

最新文章

  1. JS 字符串
  2. podfile The dependency `` is not used in any concrete target
  3. The Installation and Compilation of OpenCASCADE
  4. 面积(area)
  5. SQL修改表结构之添加主键,添加IDENTITY属性
  6. 加强版for循环
  7. git向gitHub上push和pull数据.
  8. 蓝桥杯--- 历届试题 大臣的旅费 (DFS &amp; Vector)
  9. OC中实例变量可见度、setter、getter方法和自定义初始化方法
  10. HDU_2052——画矩形
  11. 2014 I/O返回:Google连接一切
  12. github 用git bash上传项目 最后提示 Everything up-to-date 但没传上去
  13. javascript错误信息
  14. 复制命令(COPY)
  15. 不使用Visual Studio开发ASP.NET MVC应用(上篇)
  16. [转载]使用QTP测试Windows对象
  17. 通过CSS自动截取字符串长度
  18. HDU 4553 约会安排 (区间合并)【线段树】
  19. switch和if语句
  20. python nose测试框架全面介绍六--框架函数别名

热门文章

  1. Codeforces 1291 Round #616 (Div. 2) C. Mind Control(超级详细)
  2. 图论--割点--Tarjan模板
  3. 1) drf 整体了解
  4. 解决虚拟机中linux系统无法使用本机无线wifi联网的问题
  5. 使用Redis构建文章投票网站
  6. stanfordcorenlp安装教程&amp;问题汇总(importerror-no-module-named-psutil、OSError: stanford-chinese-corenlp-yyyy-MM-dd-models.jar not exists.)&amp;简单使用教程
  7. Linux文件操作命令并举例说明其作用
  8. js理论-函数中的Arguments对象
  9. linux-Curl error (37): Couldn&#39;t read a file:// file for file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-x86_64 [Couldn&#39;t open file /e tc/pki/rpm-gpg/RPM-GPG-KEY-fedora-x86_64]
  10. git:error: Your local changes to the following files would be overwritten by merge: