12/08/2018, 14:28
Xây dựng 1 abstract BaseAdapter trong RecyclerView
Đã 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.1. Xây dựng BaseAdapter Hàm setVariable ...
Đã 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.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.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); } }
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); } }
- 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(); } } }
- 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); } }
-
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_awidth="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_awidth="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_awidth="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_awidth="match_parent" android:layout_height="wrap_content" app:adapter="@{adapter}" app:layoutManager="@{layoutManager}"/> </LinearLayout> </layout>
- 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_awidth="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>
- 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_awidth="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_awidth="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:weightSum="5"> <TextView android:layout_awidth="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_awidth="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>
- 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; } }
Link
Link