Android:通用的ListView数据适配器

2023-11-19

在写Android程序时,经常会用到ListView控件进行数据展示。
使用时,需要定义一个ListView并创建其Item布局,然后对ListView设置一个适配器adapter,一般继承自BaseAdapter,同时需要定义一个ViewHolder类存储控件。但是当有很多的ListView时,这种做法就比较麻烦了,我们可以发现其中有很多通用的代码。这时候就需要抽象出一个共同的适配器出来。

(一)ListView的用法

页面布局文件和Item布局文件

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=".MainActivity">
    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:divider="#d9d9d9"
        android:dividerHeight="1dp">
    </ListView>
</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="match_parent"
    android:gravity="center_vertical">
    <ImageView
        android:id="@+id/item_image"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="8dp"
        android:background="@drawable/wx" />
    <TextView
        android:id="@+id/item_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我是ListView的Item布局"
        android:textSize="18sp" />
</LinearLayout>

Adapter和ViewHolder

构建一个数据适配器MyBaseAdapter继承BaseAdapter,此处将MyBaseAdapter类设置成MainActivity的内部类,以便对一些成员进行直接调用。在编写一个ViewHolder类,包含Item中的两个子控件。
ViewHolder的作用:通过convertView.setTag(ViewHolder v)方法与convertView进行绑定,然后当convertView复用时,直接从与之对于的convertView.getTag()中拿到convertView布局中的控件,省去了findViewById的时间

public class MainActivity extends AppCompatActivity {
    ListView mListView;
    //需要适配的数据
    String[] names = {"京东商城", "QQ", "QQ斗地主", "新浪微博", "天猫",
            "UC浏览器", "微信"};
    //图片集合
    int[] icons = {R.drawable.jd, R.drawable.qq, R.drawable.dz,
            R.drawable.xl, R.drawable.tm, R.drawable.uc, R.drawable.wx};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化ListView控件
        mListView = (ListView) findViewById(R.id.lv);
        //创建一个Adapter的实例
        MyBaseAdapter mAdapter = new MyBaseAdapter();
        //设置Adapter
        mListView.setAdapter(mAdapter);
    }
    class MyBaseAdapter extends BaseAdapter {
        //得到item的总数
        @Override
        public int getCount() {
            //返回ListView Item条目的总数
            return names.length;
        }
        //得到Item代表的对象
        @Override
        public Object getItem(int position) {
            //返回ListView Item条目代表的对象
            return names[position];
        }
        //得到Item的id
        @Override
        public long getItemId(int position) {
            //返回ListView Item的id
            return position;
        }
        //得到Item的View视图
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            //在第一次创建convertView时将控件找出,在第二次重用convertView时直接通过getTag()方法获得这些控件
            if (convertView == null) {
                convertView = LayoutInflater.from(getApplicationContext()).
                        inflate(R.layout.list_item,parent,false);
                holder = new ViewHolder();
                holder.mTextView = (TextView)convertView.findViewById(R.id. item_tv);
                holder.imageView=(ImageView) convertView.findViewById(R.id.item_image);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.mTextView.setText(names[position]);
            holder.imageView.setBackgroundResource(icons[position]);
            return convertView;
        }
        class ViewHolder {
            TextView mTextView;
            ImageView imageView;
        }
}

运行结果:
在这里插入图片描述

(二)抽象一个通用的ListView的适配器

布局文件activity_main.xml文件和Item的布局list_item.xml同上。

Java Bean类

新建一个Java Bean类,用于描述ListView中每一个Item的信息

此例中每一个item包括一个文本、一个图片(用资源号表示)

public class Bean {
    int pic; //对应Item的图片资源号
    String text;//对应Item的文本
    public Bean(int pic, String text) {
        this.pic = pic;
        this.text = text;
    }
    public int getPic() {
        return pic;
    }
    public void setPic(int pic) {
        this.pic = pic;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
}

通用的ViewHolder类

在上面的例子中,对于每一个ListView,都需要一个ViewHolder来存储Item中包含的控件,在通用的ViewHolder类中我们需要一个容器SparseArray(SparseArrays
map integers to Objects)存储一个id及其对应的view控件,我们再新建一个getView(int id),通过id获取到我们的控件即可。
同时可以为一些常用的控件设置属性值的方法。

public class ViewHolder {
    //通用的ViewHolder类,提供一个容器,专门存每个Item布局中的所有控件
    private final SparseArray<View> mViews;
    //android提供的SparseArray类,和Map类似,但是比Map效率,不过键只能为Integer
    //通过键值对保存Item中的所有控件,键为控件ID,值为控件引用
    private View mConvertView;
    private int mPosition;
    private ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        this.mViews = new SparseArray<View>();
        this.mPosition=position;
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        //setTag
        mConvertView.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
     * 当需要拿这些控件时,通过getView(id)进行获取;
     */
    public <T extends View> T getView(int viewId) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
        }
        return (T) view;
    }

    public View getConvertView() {
        return mConvertView;
    }

    // 为TextView设置字符串
    public ViewHolder setText(int viewId, String text) {
        TextView view = getView(viewId);
        view.setText(text);
        return this;
    }

    //为ImageView设置图片

    public ViewHolder setImageResource(int viewId, int drawableId) {
        ImageView view = getView(viewId);
        view.setImageResource(drawableId);
        return this;
    }
    //为ImageView设置图片
    public ViewHolder setImageBitmap(int viewId, Bitmap bm) {
        ImageView view = getView(viewId);
        view.setImageBitmap(bm);
        return this;
    }
    public int getPosition() {
        return mPosition;
    }
}

通用的Adapter类

构建一个通用的Adapter类,继承BaseAdapter类,指定其泛型,以便适应不同的Item。指定其为抽象类,以便在具体实现时设置不同控件的属性值

//编写通用的Adapter,指定泛型,以便适应不同的Java bean
public abstract class CommonAdapter<T> extends BaseAdapter {
    protected LayoutInflater mInflater;
    protected Context mContext;
    protected List<T> mDatas;
    protected final int mItemLayoutId;
    public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId) {
        this.mContext = context;
        this.mInflater = LayoutInflater.from(mContext);
        this.mDatas = mDatas;
        this.mItemLayoutId = itemLayoutId;
    }
    @Override
    public int getCount() {
        return mDatas.size();
    }
    @Override
    public T getItem(int position) {
        return mDatas.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder = getViewHolder(position, convertView, parent);
        convert(viewHolder, getItem(position));//getItem(position)的类型就是T,这句话在子类中的具体实现就是给具体的控件初始化
        //并赋值,初始化赋值控件时需要viewHolder和具体的数据Java bean,在这里抽象出来就是类型T
        return viewHolder.getConvertView();
    }

    public abstract void convert(ViewHolder helper, T item);

    private ViewHolder getViewHolder(int position, View convertView, ViewGroup parent) {
        return ViewHolder.get(mContext, convertView, parent, mItemLayoutId, position);
    }
}

设置数据源初始化Java Bean

在MainActivity.java文件中设置数据源初始化Java Bean,在设置Adapter时实现CommonAdapter类的抽象方法,实现为不同的Item设置数据

public class MainActivity extends AppCompatActivity {
    //需要适配的数据
    String[] names = {"京东商城", "QQ", "QQ斗地主", "新浪微博", "天猫", "UC浏览器", "微信"};
    //图片集合
    int[] icons = {R.drawable.jd, R.drawable.qq, R.drawable.dz,
            R.drawable.xl, R.drawable.tm, R.drawable.uc, R.drawable.wx};
    List<Bean> mDatas;//数据源  每一个item中的数据 由names和icons组成
    ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        listView = findViewById(R.id.lv);
        listView.setAdapter(new CommonAdapter<Bean>(getApplicationContext(), mDatas, R.layout.list_item) {
            @Override
            public void convert(ViewHolder helper, Bean item) {
                helper.setText(R.id.item_tv, item.getText());//为对应的TextView设置文本
                helper.setImageResource(R.id.item_image, item.getPic());//为对应的ImageView设置图片
            }
        });
    }

    public void initData() {  //初始化数据源
        mDatas = new ArrayList<Bean>();
        for (int i = 0; i < names.length; i++) {
            Bean bean = new Bean(icons[i], names[i]);
            mDatas.add(bean);
        }
    }
}

至此,成功构建了一个通用的ListView数据适配器模板,今后在使用ListView并进行数据适配时,编写与Item中对应的Java Bean,在ViewHolder类中编写设置所用控件属性值的方法,然后在Activity中实例化即可。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android:通用的ListView数据适配器 的相关文章

  • gradle更新后无法找到方法(无法编译项目)

    我尝试将项目中的 gradle 版本更新为 4 1 milestone 1 以下这些说明 https developer android com studio build gradle plugin 3 0 0 migration html
  • 如何自定义菜单项的背景颜色?

    我正在尝试定制Toolbar的弹出菜单 现在我无法设置菜单项的背景颜色 我的 styles xml 如下所示
  • 我在布局上看不到任何 FirebaseRecyclerAdapter 项目

    我试图将数据从 Firebase 数据库检索到我的布局 但我看不到任何项目FirebaseRecyclerAdapter在布局中 请帮忙 我按照一个教程展示了如何做到这一点 当我运行应用程序时 我没有看到任何项目 但我可以滚动 public
  • Android Studio:XML 布局中的“包装在容器中”

    编辑 XML 布局文件时 Eclipse 有一项称为 包裹在容器中 的功能 重新格式化 gt Android gt 可让您选择一个或多个视图并在其周围包裹您选择的布局 Android Studio中有类似的东西吗 目前正在实施中 问题 69
  • 按下按钮时应用不同的样式

    有没有办法在按下按钮时将样式应用于按钮 如果我有一种风格样式 xml
  • Android Q:file.mkdirs() 返回 false

    我们有一个应用程序 使用外部存储来存储一些临时文件 图像 二进制数据 该代码已经运行了几年 直到最近才发生重大变化 在 Android Q 上它不起作用 File f new File Environment getExternalStor
  • Bitmap.getPixels() 中的 IllegalArgumentException

    我想将数据从位图复制到int using getPixels 这是我当前的代码 int pixels new int myBitmap getHeight myBitmap getWidth myBitmap getPixels pixel
  • Android 深度链接至 Instagram 应用

    Instagram 已经发布了 iOS 深层链接的 url 方案 但尚未为 Android 创建文档 有没有办法深入链接到 Android 上的 Instagram 应用程序 以转到 Instagram 应用程序中的特定位置 例如 Inst
  • Android 构建发布失败,原因为:java.lang.ArrayIndexOutOfBoundsException:213(pr​​oguard 问题)

    我的项目使用调试构建变体构建得很好 但使用发布变体 Android Studio 会抛出 引起原因 java lang ArrayIndexOutOfBoundsException 213 可能是什么问题 如果我设置minifyEnable
  • Android 中如何通过彩信发送图片?

    我正在开发多媒体应用程序 我正在通过相机捕获一张图像 并希望将该图像和文本发送到其他号码 但我不知道如何通过彩信发送图像 MMS 只是一个 http post 请求 您应该使用执行请求额外的网络功能 final ConnectivityMa
  • Android Studio 缓慢的增量构建

    我已经完成了许多步骤来完善我们的构建系统 those https stackoverflow com questions 16775197 building and running app via gradle and android st
  • 如何检查 Android 中的同步设置

    我正在构建一个 Android 应用程序 我需要检查设备中注册的每个单独帐户的同步设置 我知道我可以通过 ContentResolver 类来做到这一点 但我遇到了一些问题 我已设法获取设备上所有帐户的列表 但我不知道在运行时从哪里获取特定
  • 没有用于警告的设置器/字段 Firebase 数据库检索数据填充列表视图

    我只是想将 Firebase 数据库中的数据填充到我的列表视图中 日志显示正在检索数据 但适配器不会将值设置为列表中单个列表项中的文本 它只说 没有二传手 场地插入值 这让我觉得我的设置器没有正确制作 但 Android Studio 自动
  • 插件“Android Bundle Support”不兼容

    大家好 自从上次更新以来 当我启动 android studio 时 我遇到了一个非常奇怪的错误 我有这个错误 插件错误 插件 Android Bundle Support 不兼容 直到构建 AI 195 SNAPSHOT 我在网上找不到任
  • 问题:为什么React Native Video不能全屏播放视频?

    我正在react native 0 57 7 中为android和ios创建一个应用程序并使用反应本机视频 https github com react native community react native video播放上传到的视频
  • 没有支持 FEATURE_CAMERA_EXTERNAL 的 Android 设备

    根据this doc https source android com devices camera external usb cameras一些 Android 设备允许使用 Camera2 API 访问外部 USB 摄像头 我检查了大约
  • 我的应用程序中的后退按钮出现问题[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想在手机关闭时清除共享首选项值 你
  • Android 后台倒计时器

    我有一个 Android 应用程序 它管理一个倒计时器 类 CountDownTimer 它显示在应用程序屏幕中 以显示到达 00 00 还剩多少时间 我现在的问题是 当我按主页按钮或启动另一个应用程序时 应用程序 计时器不会在后台运行 所
  • Android 屏幕方向错误

    我使用的是 Android HTC HERO 2 1 版本 我写的活动
  • Git 实验分支还是单独的实验存储库?

    我正在开发一个 Android 应用程序 并且在整个开发周期中一直使用 Git 现在 我想构建并发布实验性功能 供人们尝试和安装 同时仍将原始的 稳定的应用程序安装在他们的设备上 现在 这意味着我需要使用不同的包名称 这会更改开发项目中的一

随机推荐