Android 中的Adapter使用初探

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

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android ,我们可以在 Adapter 使用 OnClickListener 来实现点击事件。以下是实现步骤: 1. 在 Adapter 定义一个内部类 ViewHolder,ViewHolder 包含需要显示的 View 对象以及需要处理点击事件的 View 对象。 2. 在 onCreateViewHolder 方法创建 ViewHolder 对象,并将需要处理点击事件的 View 对象的 OnClickListener 设置为 ViewHolder 内部类定义的 OnClickListener。 3. 在 onBindViewHolder 方法将数据绑定到 ViewHolder 需要显示的 View 对象。 4. 在内部类 ViewHolder 实现 OnClickListener 接口,并在 onClick 方法处理点击事件。 以下是示例代码: ```java public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); ViewHolder viewHolder = new ViewHolder(view); viewHolder.mTextView.setOnClickListener(viewHolder); return viewHolder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.mTextView.setText(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView mTextView; public ViewHolder(View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.text_view); } @Override public void onClick(View view) { int position = getAdapterPosition(); // 处理点击事件 } } } ``` 在 ViewHolder 内部类实现 OnClickListener 接口,并在 onClick 方法处理点击事件。在 onCreateViewHolder 方法创建 ViewHolder 对象,并将需要处理点击事件的 View 对象的 OnClickListener 设置为 ViewHolder 内部类定义的 OnClickListener。在 onBindViewHolder 方法将数据绑定到 ViewHolder 需要显示的 View 对象

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值