当前位置:   article > 正文

Android适配器模式,手写ListView体验适配器_android listview 适配器

android listview 适配器

适配器模式

一. 生活小场景

​ 生活中我们将风能转换成我们的电能,如果说我们直接拿到风能,能够把我们的电灯发亮吗?是不行的,对不对,所以这是两个不能够兼容的东西,风能是不能够直接把我们的电灯泡点亮的,那怎么办?只能通过发电机将我们的风能转换成我们的电能,再通过电能去点亮电灯,所以我们的发电机就相当于适配器,它把两个不能兼容的接口,让他们兼容在了一起,宏观上来说也是风能点亮了我们的灯泡。

在这里插入图片描述

二. 适配器模式定义

​ 适配器模式 (Adapter Pattern) 是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

三. 代码小案例

我们这里举例一个电脑通过usb链接显示器的hdmi的例子。

在这里插入图片描述

/**
 * 目标
 */
public interface Target {
    void method();
}
/**
 * 具体目标是需要一个HDMI的接口
 */
public class ConcreteTarget implements Target{
    @Override
    public void method() {
        Log.w("simple ConcreteTarget", "我需要使用HDMI接口");
    }
}
/**
 * 源数据,电脑和屏幕连接
 */
public class Adaptee {
    public void method2() {
        Log.w("simple Adatee", "我需要使用USB接口");
    }
}
/**
 * 桥梁连接,继承自源数据Adaptee,并且实现目标数据的接口,意思是两边都不落下,作为桥梁
 */
public class Adapter extends Adaptee implements Target{
    @Override
    public void method() {
        //拿到源数据
        super.method2();
        //这句日志可以理解为转接头,源数据--->目标数据
        Log.w("simple Adapter", "使用了USB转HDMI线,现在可以使用在HDMI线上了");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

上面书写的这个适配器模式,可以理解为类层面的适配器模式,类适配器,灵活性不是很高。

我们修改下

/**
 * 桥梁连接,继承自源数据Adaptee,并且实现目标数据的接口,意思是两边都不落下,作为桥梁
 */
public class Adapter extends Adaptee implements Target {
    private Adaptee adaptee;

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void method() {
        //拿到源数据
        adaptee.method2();
        //这句日志可以理解为转接头,源数据--->目标数据
        Log.w("simple Adapter", "使用了USB转HDMI线,现在可以使用在HDMI线上了");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

测试代码:

public class TestActivity extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Adaptee adaptee = new Adaptee();

        Adapter adapter = new Adapter(adaptee);
        adapter.method();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

从结果看出运行成功,意味着适配器桥接usb和hdmi两个接口成功了。

在这里插入图片描述

小结:

  1. 两个不兼容的内容进行了桥接整合,通过中介者Adapter进行连接。
  2. 希望有一个类转换成另外一个类,但是两个类不兼容,又希望他们能一起工作,那就比较适合使用我们的适配器模式了,提高类的复用。

四. RecyclerView的适配器模式

我们看下面这张图,我们的app的列表是会有很多的数据,数据都是存在集合上面的,但是我们的数据,也就是我们的集合是不能直接添加到我们的ViewGroup上面去的,为什么说是ViewGroup呢,因为列表嘛,肯定不会只有一个子view,数据是不能直接通过addView的方式直接添加到我们的视图上面去显示的。

所以我们需要做一个中转,需要一个适配器Adapter,它做什么工作,它把数据给改了,把集合中的数据改成一个个对应的View,然后再把这些View,通过addView就可以添加到我们的视图上面去了,

在这里插入图片描述

接下来我们写个Demo,感受一下适配器:

测试用的Activity

public class TestActivity extends AppCompatActivity {
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = findViewById(R.id.recyclerview);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(linearLayoutManager);

        //构建源数据,
        List<String> data = new ArrayList<>();
        data.add("111");
        data.add("222");
        data.add("333");
        MyAdapter myAdapter = new MyAdapter(this, data);
        recyclerView.setAdapter(myAdapter);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

适配器

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private Context mContext;
    private List<String> mData;

    public MyAdapter(Context mContext, List<String> mData) {
        this.mContext = mContext;
        this.mData = mData;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_test, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        String data = this.mData.get(position);
        holder.textView.setText(data);
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder {
        TextView textView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.textview);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

item子view的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="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textview"
        android:textSize="30sp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="111" />
</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

父布局的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"
    android:orientation="vertical"
    >
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

最终的运行结果:

在这里插入图片描述

这就是一个经典的适配器模式的例子,也很常用,通过适配器将集合中的数据进行中转,再通过适配器addView。

五. 手写ListView体验适配器模式

我们手写自定义一个适配器,体验一下适配器模式的用途。

/**
 * 手写简单的ListView,不考虑复用
 */
public class TestListView extends ScrollView {
    private LinearLayout mContainer;
    private ListAdapter mAdapter;

    public TestListView(Context context) {
        super(context, null);
    }

    public TestListView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
        mContainer = new LinearLayout(context);
        mContainer.setOrientation(LinearLayout.VERTICAL);
        super.addView(mContainer);
    }

    public TestListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContainer = new LinearLayout(context);
        mContainer.setOrientation(LinearLayout.VERTICAL);
        super.addView(mContainer);
    }

    public void addView(View child) {
        mContainer.addView(child);
    }

    public void setAdapter(ListAdapter listAdapter) {
        this.mAdapter = listAdapter;
        int count = mAdapter.getCount();
        for (int i = 0; i < count; i++) {
            View childView = mAdapter.getView(i, mContainer);
            mContainer.addView(childView);
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

先自定义一个抽象类父类适配器,模拟ListView的两个方法,

public abstract class ListAdapter {
    //获取多少条
    public abstract int getCount();
    //获取View
    public abstract View getView(int position, ViewGroup viewGroup);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实现类

public class MyAdapter extends ListAdapter {
    private Context mContext;
    private List<String> mItems;

    public MyAdapter(Context mContext, List<String> mItems) {
        this.mContext = mContext;
        this.mItems = mItems;
    }

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

    @Override
    public View getView(int position, ViewGroup viewGroup) {
        TextView itemView = (TextView) LayoutInflater.from(mContext).inflate(R.layout.item_simple3, null);
        itemView.setText(mItems.get(position));
        return itemView;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

测试类

public class TestActivity extends AppCompatActivity {
    TestListView testListView;
    List<String> mData;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        testListView = findViewById(R.id.testView);
        mData = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            mData.add(i + "");
        }
        MyAdapter myAdapter = new MyAdapter(this, mData);
        testListView.setAdapter(myAdapter);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

activity_main的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"
    android:orientation="vertical">

    <com.example.myapplication.TestListView
        android:id="@+id/testView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></com.example.myapplication.TestListView>

</LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

itemView的xml布局

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

</TextView>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

测试结果

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/856377
推荐阅读
相关标签
  

闽ICP备14008679号