Xây dựng 1 abstract BaseAdapter trong RecyclerView
Bài đăng này đã không được cập nhật trong 3 năm
1. Mở đầu
Đã khi nào bạn chán việc phải tạo ra 1 đống các Adapter khác nhau cho mỗi RecyclerView bạn sử dụng chưa ?
Và sau đây mình sẽ giới thiệu cho các bạn cách xây dựng và dùng 1 Base Adapter dùng chung cho tất cả các RecyclerView khi dùng binding data.
2. Xây dựng BaseAdapter và BindingViewHolde
2.1. Xây dựng BaseAdapter
- Hàm setVariable
@Override
public void onBindViewHolder(BindingViewHolder holder, int position) {
final Object item = mCollection.get(position);
holder.getBinding().setVariable(BR.viewModel, item);
holder.getBinding().setVariable(BR.listener, getPresenter());
holder.getBinding().executePendingBindings();
if (mDecorator != null) {
mDecorator.decorator(holder, position, getItemViewType(position));
}
}
- Full code
/*
* Copyright (C) 2016 MarkZhai (http://zhaiyifan.cn).
*
* 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.
*/
package com.tuananh.recyclerviewdatabinding.recyclerview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import com.tuananh.recyclerviewdatabinding.BR;
import java.util.List;
/**
* Base Data Binding RecyclerView Adapter.
*
* @author markzhai on 16/8/25
*/
public abstract class BaseViewAdapter<T> extends RecyclerView.Adapter<BindingViewHolder> {
protected final LayoutInflater mLayoutInflater;
protected List<T> mCollection;
protected Presenter mPresenter;
protected Decorator mDecorator;
public BaseViewAdapter(Context context) {
mLayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public void onBindViewHolder(BindingViewHolder holder, int position) {
final Object item = mCollection.get(position);
holder.getBinding().setVariable(BR.viewModel, item);
holder.getBinding().setVariable(BR.listener, getPresenter());
holder.getBinding().executePendingBindings();
if (mDecorator != null) {
mDecorator.decorator(holder, position, getItemViewType(position));
}
}
@Override
public int getItemCount() {
return mCollection.size();
}
public void remove(int position) {
mCollection.remove(position);
notifyItemRemoved(position);
}
public void clear() {
mCollection.clear();
notifyDataSetChanged();
}
public void setDecorator(Decorator decorator) {
mDecorator = decorator;
}
protected Presenter getPresenter() {
return mPresenter;
}
public void setPresenter(Presenter presenter) {
mPresenter = presenter;
}
public interface Presenter {
}
public interface Decorator {
void decorator(BindingViewHolder holder, int position, int viewType);
}
}
2.2. Xây dựng BindingViewHolder
/*
* Copyright (C) 2016 MarkZhai (http://zhaiyifan.cn).
*
* 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.
*/
package com.tuananh.recyclerviewdatabinding.recyclerview;
import android.databinding.ViewDataBinding;
import android.support.v7.widget.RecyclerView;
/**
* @author markzhai on 16/3/18
* @version 1.0.0
*/
public class BindingViewHolder<T extends ViewDataBinding> extends RecyclerView.ViewHolder {
protected final T mBinding;
public BindingViewHolder(T binding) {
super(binding.getRoot());
mBinding = binding;
}
public T getBinding() {
return mBinding;
}
}
3. SingleTypeAdapter and MultiTypeAdapter
3.1. SingleTypeAdapter
/*
* Copyright (C) 2016 MarkZhai (http://zhaiyifan.cn).
*
* 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.
*/
package com.tuananh.recyclerviewdatabinding.recyclerview;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.annotation.LayoutRes;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Super simple single-type adapter using data-binding.
*
* @author markzhai on 16/8/22
*/
public class SingleTypeAdapter<T> extends BaseViewAdapter<T> {
protected int mLayoutRes;
public SingleTypeAdapter(Context context) {
this(context, 0);
}
public SingleTypeAdapter(Context context, int layoutRes) {
super(context);
mCollection = new ArrayList<>();
mLayoutRes = layoutRes;
}
@SuppressWarnings("unchecked")
@Override
public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new BindingViewHolder(
DataBindingUtil.inflate(mLayoutInflater, getLayoutRes(), parent, false));
}
@Override
public int getItemCount() {
return mCollection.size();
}
public void add(T viewModel) {
mCollection.add(viewModel);
notifyDataSetChanged();
}
public void add(int position, T viewModel) {
mCollection.add(position, viewModel);
notifyDataSetChanged();
}
public void set(List<T> viewModels) {
mCollection.clear();
addAll(viewModels);
}
public void addAll(List<T> viewModels) {
mCollection.addAll(viewModels);
notifyDataSetChanged();
}
@LayoutRes
protected int getLayoutRes() {
return mLayoutRes;
}
public interface Presenter<T> extends BaseViewAdapter.Presenter {
void onItemClick(T t);
}
}
3.2. MultiTypeAdapter
Dùng để xử lý với nhiều type truyền vào
/*
* Copyright (C) 2016 MarkZhai (http://zhaiyifan.cn).
*
* 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.
*/
package com.tuananh.recyclerviewdatabinding.recyclerview;
import android.content.Context;
import android.databinding.DataBindingUtil;
import android.support.annotation.LayoutRes;
import android.support.v4.util.ArrayMap;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Super simple multi-type adapter using data-binding.
*
* @author markzhai on 16/8/23
*/
public class MultiTypeAdapter extends BaseViewAdapter<Object> {
protected ArrayList<Integer> mCollectionViewType;
private ArrayMap<Integer, Integer> mItemTypeToLayoutMap = new ArrayMap<>();
public MultiTypeAdapter(Context context) {
this(context, null);
}
public MultiTypeAdapter(Context context, Map<Integer, Integer> viewTypeToLayoutMap) {
super(context);
mCollection = new ArrayList<>();
mCollectionViewType = new ArrayList<>();
if (viewTypeToLayoutMap != null && !viewTypeToLayoutMap.isEmpty()) {
mItemTypeToLayoutMap.putAll(viewTypeToLayoutMap);
}
}
@SuppressWarnings("unchecked")
@Override
public BindingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new BindingViewHolder(
DataBindingUtil.inflate(mLayoutInflater, getLayoutRes(viewType), parent, false));
}
public void addViewTypeToLayoutMap(Integer viewType, Integer layoutRes) {
mItemTypeToLayoutMap.put(viewType, layoutRes);
}
@Override
public int getItemViewType(int position) {
return mCollectionViewType.get(position);
}
public void set(List viewModels, int viewType) {
mCollection.clear();
mCollectionViewType.clear();
if (viewModels == null) {
add(null, viewType);
} else {
addAll(viewModels, viewType);
}
}
public void set(List viewModels, MultiViewTyper viewTyper) {
mCollection.clear();
mCollectionViewType.clear();
addAll(viewModels, viewTyper);
}
public void add(Object viewModel, int viewType) {
mCollection.add(viewModel);
mCollectionViewType.add(viewType);
notifyItemInserted(0);
}
public void add(int position, Object viewModel, int viewType) {
mCollection.add(position, viewModel);
mCollectionViewType.add(position, viewType);
notifyItemInserted(position);
}
public void addAll(List viewModels, int viewType) {
mCollection.addAll(viewModels);
for (int i = 0; i < viewModels.size(); ++i) {
mCollectionViewType.add(viewType);
}
notifyDataSetChanged();
}
public void addAll(int position, List viewModels, int viewType) {
mCollection.addAll(position, viewModels);
for (int i = 0; i < viewModels.size(); i++) {
mCollectionViewType.add(position + i, viewType);
}
notifyItemRangeChanged(position, viewModels.size() - position);
}
public void addAll(List viewModels, MultiViewTyper multiViewTyper) {
mCollection.addAll(viewModels);
for (int i = 0; i < viewModels.size(); ++i) {
mCollectionViewType.add(multiViewTyper.getViewType(viewModels.get(i)));
}
notifyDataSetChanged();
}
public void remove(int position) {
mCollectionViewType.remove(position);
super.remove(position);
}
public void clear() {
mCollectionViewType.clear();
super.clear();
}
@LayoutRes
protected int getLayoutRes(int viewType) {
return mItemTypeToLayoutMap.get(viewType);
}
public interface MultiViewTyper {
int getViewType(Object item);
}
}
4. Cách sử dụng SingleTypeAdapter
- Cách dùng
private void updateAdapter() {
SingleTypeAdapter<Contacts> adapter =
new SingleTypeAdapter<>(this, R.layout.item_recycler_contact);
// add viewModels
adapter.addAll(mContactsList);
// add listener
adapter.setPresenter(new ItemAdapterClickListener());
mBinding.setLayoutManager(new LinearLayoutManager(this));
mBinding.setAdapter(adapter);
}
- Khởi tạo Listener
adapter.setPresenter(new ItemAdapterClickListener());
- Full code:
package com.tuananh.recyclerviewdatabinding.view;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableArrayList;
import android.databinding.ObservableList;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.widget.Toast;
import com.tuananh.recyclerviewdatabinding.R;
import com.tuananh.recyclerviewdatabinding.databinding.ActivityMainBinding;
import com.tuananh.recyclerviewdatabinding.model.Contacts;
import com.tuananh.recyclerviewdatabinding.recyclerview.BaseViewAdapter;
import com.tuananh.recyclerviewdatabinding.recyclerview.SingleTypeAdapter;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mBinding;
private ObservableList<Contacts> mContactsList = new ObservableArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
loadData();
initViews();
updateAdapter();
}
private void loadData() {
for (int i = 0; i < 10; i++) {
mContactsList
.add(new Contacts("abc " + i, "Framgia", "0964980253", "abc@gmail.com", "Family"));
}
}
private void updateAdapter() {
SingleTypeAdapter<Contacts> adapter =
new SingleTypeAdapter<>(this, R.layout.item_recycler_contact);
// add viewModels
adapter.addAll(mContactsList);
// add listener
adapter.setPresenter(new ItemAdapterClickListener());
mBinding.setLayoutManager(new LinearLayoutManager(this));
mBinding.setAdapter(adapter);
}
private void initViews() {
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
}
public class ItemAdapterClickListener implements BaseViewAdapter.Presenter {
public void onItemClick(String values) {
Toast.makeText(getApplicationContext(), values, Toast.LENGTH_SHORT).show();
}
}
}
5. ViewBindingAdapter
- Thiết lập các hàm set cho binding data:
package com.tuananh.recyclerviewdatabinding.binding;
import android.databinding.BindingAdapter;
import android.support.v7.widget.RecyclerView;
public class ViewBindingAdapter {
@BindingAdapter("layoutManager")
public static void setLayoutManager(RecyclerView view, RecyclerView.LayoutManager manager) {
view.setLayoutManager(manager);
}
@BindingAdapter("adapter")
public static void setAdapter(RecyclerView view, RecyclerView.Adapter adapter) {
view.setAdapter(adapter);
}
}
6. Xml chứa recycler
-
Tạo file xml : activity_main.xml
-
Cách dùng :
<data>
<variable
name="adapter"
type="android.support.v7.widget.RecyclerView.Adapter"/>
<variable
name="layoutManager"
type="android.support.v7.widget.RecyclerView.LayoutManager"/>
</data>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:adapter="@{adapter}"
app:layoutManager="@{layoutManager}"/>
- Full code :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.tuananh.recyclerviewdatabinding.view.MainActivity">
<data>
<variable
name="viewModel"
type="com.tuananh.recyclerviewdatabinding.view.MainActivity"/>
<variable
name="adapter"
type="android.support.v7.widget.RecyclerView.Adapter"/>
<variable
name="layoutManager"
type="android.support.v7.widget.RecyclerView.LayoutManager"/>
</data>
<LinearLayout
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingBottom="@dimen/margin_padding_5"
android:paddingTop="@dimen/margin_padding_5"
android:text="@string/text_contact_list"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:adapter="@{adapter}"
app:layoutManager="@{layoutManager}"/>
</LinearLayout>
</layout>
7. Item RecyclerView
- Tạo file xml : item_recycler_contact.xml
- Các hàm set : app:content, app:onClickContent, app:onClickTitle, app:title, app:visibility đươc tạo trong item_text_contact.xml
- Full code:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="com.tuananh.recyclerviewdatabinding.model.Contacts"/>
<variable
name="listener"
type="com.tuananh.recyclerviewdatabinding.view.MainActivity.ItemAdapterClickListener"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_padding_10"
android:background="@drawable/contact_background"
android:orientation="vertical">
<include
layout="@layout/item_text_contact"
app:content="@{viewModel.name}"
app:onClickContent="@{() -> listener.onItemClick(viewModel.name)}"
app:onClickTitle="@{() -> listener.onItemClick(@string/text_name)}"
app:title="@{@string/text_name}"/>
<include
layout="@layout/item_text_contact"
app:content="@{viewModel.company}"
app:onClickContent="@{() -> listener.onItemClick(viewModel.company)}"
app:onClickTitle="@{() -> listener.onItemClick(@string/text_company_name)}"
app:title="@{@string/text_company_name}"/>
<include
layout="@layout/item_text_contact"
app:content="@{viewModel.mobile}"
app:onClickContent="@{() -> listener.onItemClick(viewModel.mobile)}"
app:onClickTitle="@{() -> listener.onItemClick(@string/text_mobile)}"
app:title="@{@string/text_mobile}"/>
<include
layout="@layout/item_text_contact"
app:content="@{viewModel.email}"
app:onClickContent="@{() -> listener.onItemClick(viewModel.email)}"
app:onClickTitle="@{() -> listener.onItemClick(@string/text_email)}"
app:title="@{@string/text_email}"/>
<include
layout="@layout/item_text_contact"
app:content="@{viewModel.groupName}"
app:onClickContent="@{() -> listener.onItemClick(viewModel.groupName)}"
app:onClickTitle="@{() -> listener.onItemClick(@string/text_group_name)}"
app:title="@{@string/text_group_name}"
app:visibility="@{View.GONE}"/>
</LinearLayout>
</layout>
8. ItemTextContact
- Tạo file item_text_contact.xml
- Full code :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="title"
type="String"/>
<variable
name="content"
type="String"/>
<variable
name="visibility"
type="int"/>
<variable
name="onClickTitle"
type="android.view.View.OnClickListener"/>
<variable
name="onClickContent"
type="android.view.View.OnClickListener"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="5">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:onClick="@{onClickTitle}"
android:padding="@dimen/margin_padding_5"
android:text="@{title}"
android:textStyle="bold"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:onClick="@{onClickContent}"
android:padding="@dimen/margin_padding_5"
android:text="@{content}"/>
</LinearLayout>
<include
layout="@layout/layout_line_break_form_search"
app:visibility="@{visibility}"/>
</LinearLayout>
</layout>
9. Model
- Khởi tạo model : Contacts
- Full code :
package com.tuananh.recyclerviewdatabinding.model;
/**
* Created by framgia on 27/12/2016.
*/
public class Contacts {
private String mName;
private String mCompany;
private String mMobile;
private String mEmail;
private String mGroupName;
public Contacts(String name, String company, String mobile, String email,
String groupName) {
mName = name;
mCompany = company;
mMobile = mobile;
mEmail = email;
mGroupName = groupName;
}
public String getName() {
return mName;
}
public String getCompany() {
return mCompany;
}
public String getMobile() {
return mMobile;
}
public String getEmail() {
return mEmail;
}
public String getGroupName() {
return mGroupName;
}
}
Kết quả
Link Code
Nguồn tham khảo
All rights reserved