Android之自定义实现BaseAdapter(通用适配器一)

通过前面的优化布局之后,我们接着来讲如何打造一个通用的适配器,那么通用适配器能干吗呢?很简单,减少我们对代码的书写,下面开始上代码了。

MyAdapter.java

public class MyAdapter extends BaseAdapter {
 private List<Student> data;
 public MyAdapter(List<Student> data) {
  this.data = data;
 }
 @Override
 public int getCount() {
  return data == null ? 0 : data.size();
 }
 @Override
 public Object getItem(int position) {
  return data.get(position);
 }
 @Override
 public long getItemId(int position) {
  return position;
 }
 /**
  *
  * @param position
  * @param convertView
  * @param parent
  * @return
  */
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder = null;
  if(convertView == null){
   //解析布局
   convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
   //创建ViewHolder持有类
   holder = new ViewHolder();
   //将每个控件的对象保存到持有类中
   holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
   holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
   //将每个convertView对象中设置这个持有类对象
   convertView.setTag(holder);
  }
  //每次需要使用的时候都会拿到这个持有类
  holder = (ViewHolder)convertView.getTag();
  //然后可以直接使用这个类中的控件,对控件进行操作,而不用重复去findViewById了
  holder.tvName.setText(data.get(position).getName());
  holder.tvSex.setText(data.get(position).getSex());
  return convertView;
 }

 /**
  * 通过这个类来保存当前所有的控件id
  */
 static class ViewHolder{
  TextView tvName;
  TextView tvSex;
 }
}

在上面的代码中,我们先看看有哪些代码的格式或形式都是重复在使用的,首先不难看出,public int getCount() 、public long getItemId(int position) 、public long getItemId(int position)这三个方法是不是每次都要实现呢,由此我们可以先将这些代码提取出来,放到MyBaseAdapter中,由于我们每次的重要部分是实现getView方法,所以这个方法我们不需要在这里面写,直接将MyBaseAdapter设置为抽象类就可以了,然需要实现getView的类来继承他即可,因此MyAdapter可以继承MyBaseAdapter然后实现getView方法即可

MyBaseAdapter.java

public abstract class MyBaseAdapter extends BaseAdapter {
 protected List<Student> data;
 public MyBaseAdapter(List<Student> data){
  this.data = data;
 }
 @Override
 public int getCount() {
  return data == null ? 0 : data.size();
 }

 @Override
 public Object getItem(int position) {
  return data.get(position);
 }

 @Override
 public long getItemId(int position) {
  return position;
 }
}

MyAdapter.java

public class MyAdapter extends MyBaseAdapter {
 public MyAdapter(List<Student> data) {
  super(data);
  this.data = data;
 }
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder = null;
  if(convertView == null){
   convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
   holder = new ViewHolder();
   holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
   holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
   convertView.setTag(holder);
  }
  holder = (ViewHolder)convertView.getTag();
  holder.tvName.setText(data.get(position).getName());
  holder.tvSex.setText(data.get(position).getSex());
  return convertView;
 }
 static class ViewHolder{
  TextView tvName;
  TextView tvSex;
 }
}

这样,每次自定义只需要继承MyBaseAdapter就可以了,不过还是那句话,没有最优,只有更优,所以我们还要接着优化,接着封装,那么我们接着从上面的getView方法中看,还有哪些代码是我们经常重复使用到的代码呢?其实你会发现每次我们都需要操作相同的这段代码:

ViewHolder holder = null;
  if(convertView == null){
   convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item,null);
   holder = new ViewHolder();
   holder.tvName = (TextView)convertView.findViewById(R.id.mTv1);
   holder.tvSex = (TextView)convertView.findViewById(R.id.mTv2);
   convertView.setTag(holder);
  }
  holder = (ViewHolder)convertView.getTag();
  holder.tvName.setText(data.get(position).getName());
  holder.tvSex.setText(data.get(position).getSex());
  return convertView;
 }

我们可以先再次理解下这段代码,首先我们每次都要创建一个holder持有者对象,设置到对应的converView的setTag中,然后,每次要拿到hoder对象,对hoder对象中的控件进行操作,对于上面的代码我们可以直接将他简化为以下几个步奏

1.ViewHolder holder = 拿到holder //每次拿到对应的holder对象即可
2.TextView tv = holder.getView() //拿到每个控件对应的id
3. tv.setText() //对控件进行操作
4. return view //返回view即可

下面开始写一个通用的ViewHolder通用类,来优化我们的实现,代码如下:

ViewHolder.java

public class ViewHolder {
 //被点击的当前位置
 private int position;

 //用一个map集合来保存每个控件的id,这个SparseArray是android提供的一个比map使用效率更高的一个
 //集合,但是局限是,key只能是int类型,所以当键值对涉及到key是int类型时,可以优先考虑使用这个集合
 private SparseArray<View> array;

 //复用的布局
 private View convertView;

 //上下文
 private Context context;

 //解析的布局资源id
 private int layout;
 public ViewHolder(){

 }

 //带三个构造的方法,这里将构造方法私有,防止外界去创建,通过自身的静态方法去创建对象即可
 private ViewHolder(ViewGroup parent,int position,int layout){
  this.position = position;
  this.context = parent.getContext();
  //每次创建对象,就将布局解析出来
  convertView = LayoutInflater.from(parent.getContext()).inflate(layout,null);
  //然后将对象保存到convertView对应的setTag中,方便每次该获取
  convertView.setTag(this);
  array = new SparseArray<>();
 }

 //通过这个方法,可以创建ViewHolder对象
 public static ViewHolder getHolder(View convertView, ViewGroup parent, int position,int layout){
  //每次判断converView是否为空,如果为空就直接返回这个创建的对象
  if(convertView == null){
   return new ViewHolder(parent,position,layout);
  }else{
   //不为空的情况,就跟我们上面的代码一样,每次通过复用的控件拿到对应的ViewHolder对象
   ViewHolder holder = (ViewHolder)convertView.getTag();
   //这里一定要更新下下标的位置,虽然对象相同,但是我们每次都要更新现有的位置,
   holder.position = position;
   //返回已经创建好的holder对象
   return holder;
  }
 }

 /**
 * 这个方法是通过控件id拿到对应的控件
 */
 public <T extends View> T getView(int viewId){
  //每次通过viewId键去拿到到对应的控件
  View view = array.get(viewId);
  //如果为空,表示该集合中还没有存入该控件
  if(view == null){
   //先要去通过converView拿到控件id
   view = convertView.findViewById(viewId);
   //保存到集合中,以便下次直接获取
   array.put(viewId,view);
  }
  //返回View的子类控件,采用泛型的方便是不需要强制转换了
  return (T)view;
 }
 //得到converView布局
 public View getConvertView(){
  return convertView;
 }

通过上面的代码我们就已经封装好了一个通用的ViewHolder类了,下面我们的MyAdapter.java则可以更加简单的只写一下代码了:

public class MyAdapter extends MyBaseAdapter {
 public MyAdapter(List<Student> data) {
  super(data);
 }
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder = ViewHolder.getHolder(convertView,parent,position, R.layout.list_item);
  TextView tvName = holder.getView(R.id.mTv1);
  TextView tvSex = holder.getView(R.id.mTv2);
  tvName.setText(data.get(position).getName());
  tvSex.setText(data.get(position).getSex());
  return holder.getConvertView();
 }
}

好了,上面的代码是不更简单了呢,其实我们这里只是封装了ViewHolder类哦,还有更通用的等着我们去封装呢,下次我们需要封装的就是如何把getView中的代码再一次进行封装,已达到更优。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android设计模式之适配器(Adapter)模式

    本文实例为大家分享了Android适配器模式源码,供大家参考,具体内容如下 1. 模式介绍 1.1模式的定义: 适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作. 1.2模式的使用场景: 用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出.这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换.在软件开发中有一句话正好体现了这点:任

  • Kotlin编写Android适配器Adapter

    说好今天要写一个使用Kotlin写Adapter的列子,我想了半天也没有组织好语言,直接上代码吧,有一定Android基础的小伙伴肯定是能看的懂的 package com.example.administrator.kotlintest import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import and

  • Android之自定义实现BaseAdapter(通用适配器二)

    在上一篇通用适配器一中,我们已经把ViewHolder抽取为了一个通用的持有类,极大程度上减少了我们对代码的书写,现在开始在那样的基础上在此抽取,从而达到更优.先回顾上一篇中的MyAdapter.java类中的代码,然后通过这个代码我们再一次抽取封装. public class MyAdapter extends MyBaseAdapter { public MyAdapter(List<Student> data) { super(data); } @Override public View

  • Android ListView适配器(Adapter)优化方法详解

    Android ListView的优化,在做Android项目的时候,在用到ListView 界面及数据显示,这个时候如果资源过大,对项目来说,用户体验肯定是不好的,这里就对如何优化做了详细介绍: Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View.想过没有? 在我们的列表有1000000项时会是什么样的?是不是会占用极大的系统资源? ListView的Adapter的作用如下图所示: 先看看下面

  • Android中 自定义数据绑定适配器BaseAdapter的方法

    复制代码 代码如下: public class PersonAdapter extends BaseAdapter { private List persons;// 要绑定的数据 private int resource;// 绑定的一个条目界面的id,此例中即为item.xml private LayoutInflater inflater;// 布局填充器,它可以使用一个xml文件生成一个View对象,可以通过Context获取实例对象 public PersonAdapter(Conte

  • Android SimpleAdapter适配器使用详解

    Android SimpleAdapter使用详解 HolderAdapter背景 Android的AdapterView用的比较多,ListView,GridView,Spinner等,原生的BaseAdapter对ViewHolder没有支持,每次都要,定义内部类,inflater根布局,对item内部view设置clicklistener并转发到adapter的调用者等.写的次数多了感觉很繁琐,于是写了个简单的封装,简化Adapter的编写, 仓库连接http://git.oschina.

  • Android控件系列之相册Gallery&Adapter适配器入门&控件缩放动画入门

    学习目的: 1.掌握在Android中如何建立Gallery 2.初步理解Android适配器的原理 3.实现简单的控件缩放动画 简介: 1.Gallery是Android内置的一个控件,它可以继承若干图片甚至是其他控件 2.Gallery自带了滚动播放图片功能,此功能您可以通过模拟器拖曳鼠标或者在手机上拖拽验证 3.Gallery需要适配器来传输数据,如果您不熟悉"适配器设计模式",可以将适配器理解为某厂商的电脑适配器,只要这个厂商的所有型号的电脑都能使用该适配器,也就是说,设计新型

  • 举例讲解Android应用中SimpleAdapter简单适配器的使用

    SimpleAdapter,跟名字一样,一个简单的适配器,既为简单,就只是被设计来做简单的应用的,比如静态数据的绑定,不过仍然有自定义的空间,比如说在每一个ListItem中加一个按钮并添加响应事件.首先还是先看一下SimpleAdapter的定义吧,直接翻译下SDK doc 吧: 这是一个简单的适配器,可以将静态数据映射到XML文件中定义好的视图.你可以指定由Map组成的List(比如ArrayList)类型的数据.在ArrayList中的每个条目对应List中的一行.Maps包含每一行的数据

  • Android之自定义实现BaseAdapter(通用适配器三)

    在上一篇中,我们说过,在setData中如果有很多控件的话,我们还是要在该方法中写入很多代码,为了降低开发的方便性,本次就在此基础上再一次优化.实现原理是这样的,每次在setData中都要查找控件,然后setXXX()什么的,我们可以把这写实现放如到ViewHolder中去,在ViewHolder中写入一个链式的方法,来帮助我们来实现功能(关于ViewHodler类的代码我就不再重复写了,代码在此:Android之自定义实现BaseAdapter(通用适配器一) ),链式方法如下: public

  • Android之自定义实现BaseAdapter(通用适配器一)

    通过前面的优化布局之后,我们接着来讲如何打造一个通用的适配器,那么通用适配器能干吗呢?很简单,减少我们对代码的书写,下面开始上代码了. MyAdapter.java public class MyAdapter extends BaseAdapter { private List<Student> data; public MyAdapter(List<Student> data) { this.data = data; } @Override public int getCoun

  • Android自定义实现BaseAdapter的优化布局

    上一篇中我们介绍了自定义实现BaseAdapter的普通实现布局,然而上一章也说了普通实现的方式效率会很低,而且对系统开销也很大,所以,那样的实现是为了让初学者能知道可以这样使用,在实际项目中不可能使用那种方式的,要是你在做项目的时候使用普通布局方式,我敢保证,不过试用期你的老板就给你飞机票走人了,好了,闲话少说,本次讲解一下优化布局的实现,看完代码后,你会觉得,其实很简单. MainActivity.java public class MainActivity extends AppCompa

  • Android 中RecyclerView通用适配器的实现

    Android 中RecyclerView通用适配器的实现 前言: SDK的5.0版本出来已经N久了,可以说是已经经过许多人的检验了,里面的新控件不能说是非常完美,但也是非常好用了,其中最让我喜爱的就是RecyclerView了,可以完美替代ListView和GridView(除了添加headerview和footview了,网上有许多解决方式.这个下面会以一种简单的方式顺带解决,肯定为大家省心),而且可以代码动态切换这两种布局方式以及瀑布流布局.相关切换方式网上有很多,大家自行搜索,我就不贴连

  • Android自定义实现BaseAdapter的普通实现

    对于ListVie来说,数据项的设置有很多种方式,而自定义实现BaseAdapter是最经常用的了,那么这里我们来讲解一下自定义实现BaseAdapter的普通实现. MainActivity.java public class MainActivity extends AppCompatActivity { //数据源 private List<String> data; //ListView控件 private ListView mList; @Override protected voi

  • Android自定义Dialog实现通用圆角对话框

    前言:圆角对话框在项目中用的越来越多,之前一篇文章有介绍过使用系统的AlertDialog+CardView(Android中使用CardView实现圆角对话框)实现了圆角对话框的样式,今天介绍自定义Dialog实现通用的圆角对话框. 效果图: 1.继承自AlertDialog,重写onCreat /** * Created by ruancw on 2018/6/7. * 自定义的带圆角的对话框 */ public class RoundCornerDialog extends AlertDi

  • Android 使用自定义RecyclerView控件实现Gallery效果

    上篇文章给大家介绍了Android 自定义 HorizontalScrollView 打造多图片OOM 的横向滑动效果.其实制作横向滚动的不得不说另一个控件,就是Google官方最近新增加的RecyclerView,据说是ListView的升级版本,本篇文章,首先介绍RecyclerView的用法,然后经行一定的分析:最后自定义一下RecyclerView实现我们需要的相册效果. 1.RecyclerView的基本用法 首先主Activity的布局文件: <RelativeLayout xmln

  • Android编程自定义搜索框实现方法【附demo源码下载】

    本文实例讲述了Android编程自定义搜索框实现方法.分享给大家供大家参考,具体如下: 先来看效果图吧~ 分析:这只是模拟了一个静态数据的删除与显示 用EditText+PopupWindow+listView实现的 步骤: 1.先写出搜索框来-activity_mian布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sc

  • Android编程自定义AlertDialog样式的方法详解

    本文实例讲述了Android编程自定义AlertDialog样式的方法.分享给大家供大家参考,具体如下: 开发的时候,通常我们要自定义AlertDialog来满足我们的功能需求: 比如弹出对话框中可以输入信息,或者要展示且有选择功能的列表,或者要实现特定的UI风格等.那么我们可以通过以下方式来实现. 方法一:完全自定义AlertDialog的layout.如我们要实现有输入框的AlertDialog布局custom_dialog.xml: <?xml version="1.0"

随机推荐