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线上了");
    }
}

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

我们修改下

/**
 * 桥梁连接,继承自源数据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线上了");
    }
}

测试代码:

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();
    }
}

从结果看出运行成功,意味着适配器桥接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);
    }
}

适配器

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);
        }
    }
}

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>

父布局的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>

最终的运行结果:

在这里插入图片描述

这就是一个经典的适配器模式的例子,也很常用,通过适配器将集合中的数据进行中转,再通过适配器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);
        }

    }
}

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

public abstract class ListAdapter {
    
    
    //获取多少条
    public abstract int getCount();
    //获取View
    public abstract View getView(int position, ViewGroup viewGroup);
}

实现类

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;
    }
}

测试类

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);
    }
}

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>

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>

测试结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_46039528/article/details/130569857