• Stars
    star
    99
  • Rank 341,386 (Top 7 %)
  • Language
    Java
  • Created over 7 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Super simple and easy to use common multi-type-adapter by android data-binding

MultiTypeAdapter

Implement a super simple, powerful, and easy to use MultiTypeAdapter for RecyclerView by android databinding, it is only about 100 lines code and just one java file, use this adapter, you can never to implement kinds of ViewHolder anymore.

I write a very detail tutorial to explain how to implement this MultiTypeAdapter, and how to use it to implement a complete sample that support refresh, load more, retry, header item, emtpy item, error item, footer item, any kinds of data item step by step.

Tutorial

  1. Escape the nightmare of adapter and viewholder by android databinding (1)
  2. Escape the nightmare of adapter and viewholder by android databinding (2)

Sample

  1. Demo HeaderItem, EmptyItem, ErrorItem, refresh, load more, load error and retry:

  2. Demo load more but has no more data:

  3. Polish the UI, add event handler for item:

The sample includes following features, I think it should fullfill 90% needs:

  1. Refresh
  2. Load more
  3. Support header item
  4. Support empty item and enable refresh again
  5. Support error item and enable refresh again
  6. Support footer item, includes 3 states: loading, load error and enable retry, no more data
  7. Support any kind of data item, here just demo ImageItem and TextItem

Download APK | GitHub

There are two folders in this project, MultiTypeAdapterSample and MultiTypeAdapterTutorial, their codes are nearly same, the latter is created for the above tutorial articles, I tag the every key step so you can easily compare the code with article.

Getting Started

Add JitPack as library source in your project build.gradle:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Then, add dependency in your app module build.gradle:

dependencies {
    compile 'com.github.baurine:multi-type-adapter:${latest-version}'
}

latest-version: see top jitpack badge.

And enable databinding in your app module build.gradle:

android {
    ...
    dataBinding {
        enabled = true
    }
}

Usage

Please read the above super detail tutorial to learn how exactly to use it. Following are some simple instruction extract from tutorial.

After you use this MultiTypeAdapter, you just need to implement kinds of items, and add to or remove from adapter at the right time. The item represents a whole body that display in recyclerview, includes layout, data and event, so it is a wrapper, wrap the layout, data model and event handler together, but the data model and event handler are not necessary, just layout is required, it depends on what's the kind of item. All items must inherit from IItem interface:

public interface IItem {
    // get the xml layout this type item used in
    int getLayout();

    // get the variable name in the xml
    int getVariableId();
}

getLayout() method should return the xml layout, likes R.layout.item_header, and getVariableId() return the variable name this item used in xml, likes BR.item. Becasuse we usually use a same variable name in all items, and the event handler, usually it can be a View.OnClickListener, so we define a BaseItem:

public abstract class BaseItem implements MultiTypeAdapter.IItem {
    @Override
    public int getVariableId() {
        return BR.item;
    }

    ////////////////////////////////////////////
    // handle event
    private View.OnClickListener onClickListener;

    public View.OnClickListener getOnClickListener() {
        return onClickListener;
    }

    public void setOnClickListener(View.OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }
}

Here is an example, a most simple item - HeaderItem, just has layout, no data and no event:

public class HeaderItem extends BaseItem {
    @Override
    public int getLayout() {
        return R.layout.item_header;
    }
}

And HeaderItem used in item_header.xml:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="item"
            type="com.baurine.multitypeadaptersample.item.HeaderItem"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:background="@drawable/x_border"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="24dp"
            android:text="This is a HeaderItem"
            android:textSize="20sp"
            android:textStyle="bold"/>

    </LinearLayout>
</layout>

A most complex item - ImageItem, display a random image, and you can like it, hide it, and comment it, the image data from ImageModel:

ImageModel:

public class ImageModel extends BaseModel {
    @Override
    public MultiTypeAdapter.IItem createItem(MultiTypeAdapter adapter) {
        return new ImageItem(this, adapter);
    }

    ////////////////////////////////////////
    public final String url;
    public boolean liked;

    public ImageModel() {
        super();
        url = "https://unsplash.it/200/200?random&" + new Random().nextInt(40);
        liked = (new Random()).nextBoolean();
    }
}

ImageItem:

public class ImageItem extends BaseItem {
    @Override
    public int getLayout() {
        return R.layout.item_image;
    }

    ///////////////////////////////////////
    public ImageItem(ImageModel imageModel, final MultiTypeAdapter adapter) {
        this.imageModel = imageModel;

        setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                switch (view.getId()) {
                    case R.id.tv_like:
                        toggleLiked();
                        adapter.notifyItemChanged(adapter.findPos(ImageItem.this));
                        break;
                    case R.id.tv_hide:
                        adapter.notifyItemRemoved(adapter.removeItem(ImageItem.this));
                        break;
                    case R.id.tv_comment:
                        CommonUtil.showToast(view.getContext(),
                                "TODO: comment image, id: " +
                                        String.valueOf(getId()));
                        break;
                }
            }
        });
    }

    ///////////////////////////////////////
    // data model part
    private final ImageModel imageModel;

    public String getUrl() {
        return imageModel.url;
    }

    public boolean isLiked() {
        return imageModel.liked;
    }

    public int getId() {
        return imageModel.id;
    }

    public void toggleLiked() {
        imageModel.liked = !imageModel.liked;
    }
}

ImageItem used in item_image.xml:

<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="item"
            type="com.baurine.multitypeadaptersample.item.ImageItem"/>
    </data>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:cardCornerRadius="2dp">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:scaleType="centerCrop"
                app:error="@{@drawable/ic_launcher}"
                app:imageUrl="@{item.url}"
                app:placeholder="@{@drawable/ic_launcher}"/>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="#c0ffffff">

                <include
                    layout="@layout/include_actions"
                    app:liked="@{item.liked}"
                    app:onClickListener="@{item.onClickListener}"/>

            </LinearLayout>
        </FrameLayout>
    </android.support.v7.widget.CardView>
</layout>

<!-- include_actions.xml-->
<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="liked"
            type="Boolean"/>
        <variable
            name="onClickListener"
            type="android.view.View.OnClickListener"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/tv_like"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:onClick="@{onClickListener::onClick}"
            android:paddingVertical="@{8}"
            android:text="@{liked ? `ๅ–ๆถˆ่ตž` : `็‚น่ตž`}"
            android:textColor="@{liked ? @android:color/holo_red_light : @android:color/darker_gray}"/>

        <TextView
            android:id="@+id/tv_hide"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:onClick="@{onClickListener::onClick}"
            android:paddingVertical="@{8}"
            android:text="้š่—"/>

        <TextView
            android:id="@+id/tv_comment"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:onClick="@{onClickListener::onClick}"
            android:paddingVertical="@{8}"
            android:text="่ฏ„่ฎบ"/>
    </LinearLayout>
</layout>

Then call adapter.addItem(), adapter.removeItem(), adapter.notifyItemChanged(adapter.findPos(item)) to operate the adapter at the right time. Following is an example to handle the network response result:

private void retrieveItems(boolean loadMore) {
    // result = 0, network error
    // result = 1, empty
    // result = 2, last page data
    // result = 3 and other, normal result
    int resultType = (new Random()).nextInt(100) % 5;
    if (resultType == 0) {
        adapter.addItem(loadMore ? footerItem.setState(FooterItem.ERROR) : errorItem);
    } else if (resultType == 1) {
        adapter.addItem(loadMore ? footerItem.setState(FooterItem.NO_MORE) : emptyItem);
    } else if (resultType == 2) {
        addDataItems(PER_PAGE_COUNT / 2);
        // here depends whether you want to display no more data state
        // if you don't want to display this state when has no more data
        // then just don't add it back
        adapter.addItem(footerItem.setState(FooterItem.NO_MORE));
    } else {
        addDataItems(PER_PAGE_COUNT);
        // pre-display loading state to improve user experience
        adapter.addItem(footerItem.setState(FooterItem.LOADING));
    }
}

License

Copyright 2017 baurine.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

language-study

Learn foreign language
76
star
2

vscode-pangu

VS Code extension for pangu, add whitespace between Chinese and English
JavaScript
56
star
3

react-in-rails-practice

A practice to use react in rails by webpacker and react-rails gem, support SSR
Ruby
22
star
4

gitlab-time-report

A chrome extension for reporting gitlab issues spent time, made by React+TypeScript+Webpack+Firebase+Bulma
TypeScript
17
star
5

study-note

Record study notes
8
star
6

githook

A ruby gem that help to setup git hooks easily, base on Rake, inspired from Capistrano
Ruby
7
star
7

android-location-study

Learn android location
Java
6
star
8

instagram-material

An instagram-like app by material design follow tutorial
Java
5
star
9

android-data-binding-study

Learn android data-binding
Java
5
star
10

permission-util

A wrapper for android terrible native permission request api
Java
5
star
11

uninterrupted-audio-player

Uninterrupted audio player by turbolinks
Ruby
3
star
12

rails-study

Learn rails
Ruby
3
star
13

jing-sketch-xcode

Learn and practice sketch follow ้™็”ต's <Sketch + Xcode ๅŒๅ‰‘ๅˆ็’ง> video tutorial and book.
Objective-C
2
star
14

grafana-value-formats

Extract code about value formats from grafana repo and did some slight changes
TypeScript
2
star
15

shield

Shield wechat moments
Java
2
star
16

git-hooks-sample

Sample for some git hooks
Ruby
2
star
17

checkstyle-sample

A sample and guide to demo how to use checkstyle tool to check android project code style in Android Studio
Java
2
star
18

swag-example

An example to demo how to use swag, and auto generate the TS code for frontend.
TypeScript
2
star
19

html5-dnd-summary

Summary for HTML5 drag and drop by native and react
JavaScript
2
star
20

react-training

do react training for co-workers
TypeScript
1
star
21

test-es-build

test using esbuild-loader in CRA project
TypeScript
1
star
22

customized-loki-ds-plugin

Customized Loki DataSource Plugin for Grafana
TypeScript
1
star
23

egghead-beautiful-react-dnd

JavaScript
1
star
24

nextjs-study

Learn SSR and Next.js
JavaScript
1
star
25

android-test-study

Learn android test
Java
1
star
26

hide-osd-header

a OSD (OpenSearch Dashboards) plugin to hide the page header (menu, nav)
TypeScript
1
star
27

vfsgen-go-embed-demo

A simple demo to show how to use vfsgen and go native embed to bundle frontend code to backend go code
TypeScript
1
star
28

js-study

Learn JavaScript
JavaScript
1
star
29

swipebackview

A very simple and less feature custom view to help swipe back the activity, it is not powerful but just works
Java
1
star
30

baurine.github.io

Baurine's blog
CSS
1
star
31

react-tree-view

A simple React TreeView component with flat data structure
TypeScript
1
star