What is a MergeAdapter?

A new feature about Adapter, MergeAdapter, was released in the latest RecyclerView :1.2.0-alpha02. We can “merge” adapters, or “add” adapters.

It may not sound that easy to understand. We first look at the following RecyclerView should be how to achieve?

Source address at the end of the article.

It’s actually pretty simple to implement, and most people can think of using multiple itemViews based on their current knowledge. There are three types to distinguish, Teacher, Student and Foot. Different types correspond to different layout files, which also correspond to different business logic.

That’s what we’ve been doing for a long time. So, did you ever think there was something wrong with that? The coupling is too high. In the example above, one Adapter is responsible for rendering three sets of view layouts. What about four, five, or more? In terms of scalability, this solution is not reasonable.

In this case, let each Adapter be responsible for only one set of view layouts. Not only reduce the code coupling degree, but also easy to expand. If a new layout type appears, a second Adapter is sufficient. In the example above, three adapters are required: TeahcherAdapter, StudentAdapter, and FootAdapter.

The TeahcherAdapter is responsible for displaying the view of the Teacher section at the top of the list. The StudentAdapter is responsible for presenting the view of the Student section of the body of the list. The FootAdapter is responsible for showing a view of the loaded state at the bottom of the list, including loaded and no more data.

It looks beautiful, each doing his job and not interfering with the other. However, how many adapters can your RecyclerView accept?

    public void setAdapter(@Nullable Adapter adapter) {
        // bail out if layout is frozen
        setLayoutFrozen(false);
        setAdapterInternal(adapter, false.true);
        processDataSetCompletelyChanged(false);
        requestLayout();
    }
Copy the code

RecyclerView is clearly monogamous. With the setAdapter() method, we can only set one Adapter to RecyclerView.

In RecyclerView :1.2.0-alpha02, in fact, we can still set only one Adapter, but this Adapter can be MergeAdapter, a can do addition Adapter.

Go straight to the code.

private val teacherAdapter by lazy { TeacherAdapter() }
private val studentAdapter by lazy { StudentAdapter() }
private val stateAdapter by lazy { StateAdapter() }

val mergeAdater  = MergeAdapter(teacherAdapter, studentAdapter, footAdapter)

recyclerView.adapter = mergeAdapter
Copy the code

The method of use is so unpretentious, even a little boring. The order of arguments in the MergeAdapter constructor identifies the order in which the data in the list will be displayed.

The first layout is Teacher. In real life development, it can often be used as a Header View.

class TeacherAdapter : ListAdapter<Teacher, TeacherViewHolder>(TeacherDiffCallback()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TeacherViewHolder {
        return TeacherViewHolder(
            ItemTeacherBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false))}override fun onBindViewHolder(holder: TeacherViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

}
Copy the code

The second layout is Student. That is, the actual tabular data in actual development.

class StudentAdapter : ListAdapter<Student, StudentViewHolder>(StudentDiffCallBack()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StudentViewHolder {
        return StudentViewHolder(
            ItemStudentBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false))}override fun onBindViewHolder(holder: StudentViewHolder, position: Int) {
       holder.bind(getItem(position))
    }
}
Copy the code

The final piece of the layout is the state layout, which is the usual Footer. Contains loading, loading failed and no more data, three states.

class FootAdapter : ListAdapter<LoadState, StateViewHolder>(StateDiffCallBack()) {
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StateViewHolder {
        return StateViewHolder(
            ItemStateBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false))}override fun onBindViewHolder(holder: StateViewHolder, position: Int) {
        holder.bind(getItem(position))
    }
}
Copy the code

It’s the same as the usual Adapter notation.

What are the benefits?

As we all know, RecyclerView is a class library with extremely sophisticated design. Many design patterns can be found in the source code. MergeAdapter is no exception.

The single responsibility principle, which greatly reduces code coupling, is that one Adapter is responsible for multiple layouts and that each Adapter handles only one layout.

In the face of new demand, need to add a new type of RecyclerView View. All we need to do is add a new Adapter without modifying the previous Adapter code. Open to extension, closed to modification, this is the open closed principle.

What are the restrictions?

As shown in the example above, MergeAdapter data is presented in the order of arguments in the constructor, and data of the same type is always presented centrally. Therefore, for complex views of uncertain, dynamically typed types, MergeAdapter cannot handle them.

Another point, not a limitation, but an expectation of MergeAdapter capabilities. Support for multiple LayoutManagers would be even better. In multi-type RecyclerView, part of the data need horizontal sliding display, part of the data need vertical sliding display, this situation has been more common.

The last

Some of MergeAdapter’s learning resources.

Introduction to Android Development team:

Medium.com/androiddeve…

Nuggets of gold

Juejin. Cn/post / 684490…

Source code address:

Github.com/lulululbj/S…


This is bingxin said, welcome to follow my public number, the first time to bring you the latest developments in Android.