Android 中的Adapter使用初探

原创 2016年08月28日 18:53:52

Android 中的Adapter


前言

Adapter作为安卓中经常用到并且重要的一个类,是数据与视图进行交互的桥梁,官方给的的解释如下:

An Adapter object acts as a bridge between an AdapterView and the underlying data for that view. The Adapter provides access to the data items. The Adapter is also responsible for making a View for each item in the data set.

大致意思是:Adapter作为视图(AdapterView)与数据交互的桥梁,是数据的入口;同时也能够对每一项数据进行操作

可能会有个疑问,难道每次赋值都需要Adapter?

答案是否定的,注意原文中的viewAdapterView,指明了使用的范围。

那什么是AdapterView呢?

An AdapterView is a view whose children are determined by an Adapter.

See ListView, GridView, Spinner and Gallery for commonly used subclasses of AdapterView.

可以看到,AdapterView是一个View,但是它的子类由Adapter(可能有各种各样的Adapter,此处是泛指)决定,如ListViewGridView

所以,我们可以知道如果一个View直接或间接继承了AdapterView,那么它数据与视图的绑定就需要用Adapter来实现,这样做在布局复杂时能降低代码的耦合性,数据与视图完全分离,通过Adapter做为桥梁将它们连接起来。

官方文档也给出以一些封装好的Adapter
|这里写图片描述


使用

下面简单介绍几个常用的Adapter

ArrayAdapter

通常与ListView、RecyclerView等列表控件一起使用,数据可以是简单的String 类型,也可以是复杂类型,如ArrayAdapter< User > 此处的User就是一个复杂的数据类型。

简单使用

先看下XML文件,只有一个ListView控件

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </ListView>

</LinearLayout>

实现代码

...
//简单的String类型item
 ArrayAdapter<String> arrayAdapter;
        arrayAdapter = new ArrayAdapter<String>(
                this,
                //此处为方便显示,引用系统的布局文件
                android.R.layout.simple_list_item_1,
                new String[]{"小明", "小红", "小花", "小胖"});
//设置Adapter
mListView.setAdapter(arrayAdapter);
...

运行结果:
这里写图片描述

当布局比较复杂时,或者item中需要显示多项数据时,需要继承 ArrayAdapter< T >

item 布局

<?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="80dp">

    <ImageView
        android:id="@+id/icon_head"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_alignParentStart="true"
        android:layout_centerInParent="true"
        android:layout_marginStart="10dp"
        android:src="@drawable/icon_common_food"/>

    <TextView
        android:id="@+id/tv_user_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginStart="10dp"
        android:layout_toRightOf="@+id/icon_head"
        android:text="糊涂虫"
        android:textColor="@color/colorText"
        android:textSize="14sp"/>

    <TextView
        android:id="@+id/tv_user_level"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/iv_level_img"
        android:text="初级画师"
        android:textColor="@color/colorRed"
        android:textSize="12sp"/>

    <ImageView
        android:id="@+id/iv_level_img"
        android:layout_width="12dp"
        android:layout_height="12dp"
        android:layout_centerInParent="true"
        android:layout_marginLeft="20dp"
        android:layout_toRightOf="@+id/tv_user_name"
        android:src="@drawable/icon_common_assessment_selected"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_alignParentBottom="true"
        android:background="@color/colorDivLine"/>

    <ImageView
        android:id="@+id/imageView6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignStart="@+id/tv_user_name"
        android:layout_below="@+id/tv_user_name"/>

</RelativeLayout>

这算是稍微复杂一点的布局,此时仅仅用 String 类型就不行了,需要自己定义一个Adapter 继承自ArrayAdapter

首先定义Bean 类

public class User {
    private String name;
    private String career;
    private int iconHead;

    public String getCareer() {
        return career;
    }

    public void setCareer(String career) {
        this.career = career;
    }

    public int getIconHead() {
        return iconHead;
    }

    public void setIconHead(int iconHead) {
        this.iconHead = iconHead;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

定义一个UserAdapter 继承 ArrayAdapter

public class UserAdapter extends ArrayAdapter<User> {

    /**
     * Context:上下文
     * resource:布局文件ID
     * objects:数据对象
     */

    //定义资源文件ID,也可以不要这个参数直接指定
    private int resourceId;
    private Context mContext;

    //直接指定布局文件
//    public UserAdapter(Context context, List<User> objects) {
//        super(context, R.layout.item_list_demo, objects);
//    }

    public UserAdapter(Context context, int resourceId, List<User> objects) {
        super(context, resourceId, objects);
        this.resourceId = resourceId;
        this.mContext = context;
    }



    //重写getView方法
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        User user = getItem(position);
        View view = LayoutInflater.from(mContext).inflate(resourceId, null);
        ImageView iconHeader = (ImageView) view.findViewById(R.id.icon_head);
        TextView userName = (TextView) view.findViewById(R.id.tv_user_name);
        TextView userCareer = (TextView) view.findViewById(R.id.tv_user_level);

        //设置头像和昵称
        iconHeader.setImageResource(user.getIconHead());
        userName.setText(user.getName());
        userCareer.setText(user.getCareer());

        return view;
    }
}

然后再Activity中调用,与string的时候类似

  List<User> users = new ArrayList<User>();

        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setCareer("逗比逗");
            user.setName("哈哈");
            user.setIconHead(R.drawable.icon_common_doutu);
            users.add(user);
        }

        UserAdapter adapter = new UserAdapter(this, R.layout.item_list_demo, users);
        mListView.setAdapter(adapter);

显示效果
这里写图片描述

SimpleAdapter

使用方便,可扩展性强,简化控件的定义方式(findViewById),数据类型通常是HashMap

List<Map<String, Object>> users = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < 10; i++) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("userName", "呵呵");
            map.put("career", "逗比逗");
            map.put("iconHeader", R.drawable.icon_common_food);
            users.add(map);
        }


        SimpleAdapter simpleAdapter = new SimpleAdapter(
                this, users, R.layout.item_list_demo,
                //key值
                new String[]{"userName", "career", "iconHeader"},
                //对应的控件
                new int[]{R.id.tv_user_name, R.id.tv_user_level, R.id.icon_head});


        mListView.setAdapter(simpleAdapter);

显示效果
这里写图片描述

可以看到,布局文件还是跟之前一样,但是代码减少了不少,这里不需要再单独写Adapter,不需要指定布局,只用指定控件的id可以了(但所指定的必须在同一个布局中),特别方便。在做布局或者数据测试的时候经常用到,但是如果布局中有一些事件要处理的话,就不合适了,这时候需要自定义adapter

自定义Adapter

有时候布局比较复杂,而且布局中的还有各种事件要处理,这时候需要自定义Adapter,继承自BaseAdapter

同样是上面的布局,我们用自定义Adapter来实现,首先定义Adapter

public class CustomAdapter extends BaseAdapter {

    private List<User> mUsers;
    private LayoutInflater mInflater;

    private int selectedPosition = -1;

    //设置选中的位置
    public void setSelectedPosition(int position) {
        selectedPosition = position;
        Logger.d(selectedPosition);
    }

    public CustomAdapter(Context context, List<User> users) {
        mInflater = LayoutInflater.from(context);
        this.mUsers = users;
    }

    @Override
    public int getCount() {
        return mUsers.size();
    }

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        User user = (User) getItem(position);
        View view = null;
        ViewHolder viewHolder;

        if (convertView != null) {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag();
        } else {
            view = mInflater.inflate(R.layout.item_list_demo, null);
            viewHolder = new ViewHolder(view);
            view.setTag(viewHolder);
        }

        //设置头像和昵称
        viewHolder.mIconHead.setImageResource(user.getIconHead());
        viewHolder.mTvUserName.setText(user.getName());
        viewHolder.mTvUserLevel.setText(user.getCareer());


        //设置选中事件,选中时将当前item设为黄色
        if (selectedPosition == position) {
            viewHolder.mRl.setBackgroundColor(Color.YELLOW);
        } else {
            viewHolder.mRl.setBackgroundColor(Color.WHITE);
        }

        return view;
    }

    static class ViewHolder {
        @BindView(R.id.icon_head)
        ImageView mIconHead;
        @BindView(R.id.tv_user_name)
        TextView mTvUserName;
        @BindView(R.id.tv_user_level)
        TextView mTvUserLevel;
        @BindView(R.id.iv_level_img)
        ImageView mIvLevelImg;
        @BindView(R.id.imageView6)
        ImageView mImageView6;
        @BindView(R.id.rl)
        RelativeLayout mRl;

        ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }
}

有没有感觉这个Adapter很熟悉,没错,与之前的自定义的ArrayAdapter 基本上差不多。其实ArrayAdapter 也是继承自BaseAdapter,封装程度更高,暴露的方便比较少。因为从类名就可以看到其用处,而BaseAdapter是基类,通过集成它你可以定义任何你想要的Adapter。

注:代码中用到了注解和缓存模式

Activity调用,方法大同小异

List<User> users = new ArrayList<User>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setCareer("逗比逗");
            user.setName("哈哈");
            user.setIconHead(R.drawable.icon_common_doutu);
            users.add(user);
        }

        final CustomAdapter adapter = new CustomAdapter(this, users);
        mListView.setAdapter(adapter);

        //设置ListView的点击事件
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                adapter.setSelectedPosition(position);
                //通知布局改变了,不加这句不显示效果
                adapter.notifyDataSetChanged();
            }
        });

看看效果
这里写图片描述

至此,常用的Adapter基本上介绍完了,如果碰到比较复杂的需求可以尝试自定义Adapter,正常开发中基本上都是自定义Adapter。系统提供的一般测试数据的时候用


尾巴

简单的介绍了几个常用的Adapter的使用,如果有不对的地方还请指正哈。

当然,可能你会觉得这些Adapter使用好烦啊,又要定义控件,又要设置数据的,能不能用更少的代码实现更多的功能。答案是,当然有了!所以才说,懒人改变世界,233333333333

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

android开发游记:RecyclerView无法添加onItemClickListener最佳的高效解决方案

自从RecyclerView发布以来,由于其高度的可交互性被广泛使用。但是RecyclerView确没有像ListView一样提供onItemClickListener却让人比较难过,网上搜索了一番有...

android中adapter的使用

  • 2015年06月18日 19:07
  • 2.53MB
  • 下载

Android中关于Adapter的使用(上)ArrayAdapter

在Android应用的开发中,ListView是最常用的一个列表显示控件,微博,联系人啊,反正只要涉及多数据展示的情况,都会用到ListView(另外就是GridView)。那么ListView又是如...

Android中常用Adapter的使用实例

  • 2014年08月30日 23:17
  • 1.47MB
  • 下载

Android Adapter的使用

  • 2015年10月26日 10:31
  • 3.66MB
  • 下载

Android的Adapter接口使用详解

Adapter接口主要用于为ListView和Spinner等容器(即AdapterView)提供列表项,是搭建列表项布局与数据之间的链接桥梁。Adapter负责提供每个"列表项"组件,Adapter...

Android开发系列(十四):ListView用法、对ListView监听的三种方法以及ListView中Adapter的使用方法

一、ArrayAdapter的介绍以及ListView的用法: Adapter是数据和视图之间的桥梁,数据在adapter中做处理,然后显示到视图上面。就是用来绑定数据用的。 用一个小例子来介绍一...

Android 使用adapter的两种回调数据方式

1、首先创建一个listView列表,用于显示数据 item布局使用简单的一行文字显示,主要是将点击的位置回调回使用listView的类文件之中...

android使用ListView和Adapter.getView Recycler的工作原理

正文始 项目用到ListView,由于要用到ImageView,图片源不是在资源里面的,没法使用资源ID,因此无法直接使用 SimpleAdapter,要自己写一个Adapter。在使用ListVie...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 中的Adapter使用初探
举报原因:
原因补充:

(最多只允许输入30个字)