寫(xiě)在前面
如果每次都直接寫(xiě)一個(gè)Adapter,實(shí)在是特別的繁瑣翼抠,代碼太多咙轩,所以我在仔細(xì)學(xué)習(xí)之后,也在網(wǎng)上大神的博客之中取了不少經(jīng)阴颖,現(xiàn)在準(zhǔn)備好好打造一個(gè)萬(wàn)能的適配器活喊。
之前我有一篇博客是寫(xiě)RecyclerView的基本使用的,我們現(xiàn)在就接著上一篇博客繼續(xù)量愧,一個(gè)暫時(shí)沒(méi)有優(yōu)化過(guò)的Adapter是這個(gè)樣子的:
package com.lay.laykypro.adapter.ClidFragment;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.lay.laykypro.R;
import java.util.HashMap;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainClidRecyclerViewAdapter extends RecyclerView.Adapter<MainClidRecyclerViewAdapter.MainClidHolder> {
private List<HashMap<String, Object>> mdataList;
private Context mContext;
private LayoutInflater mLayoutInflater;
//設(shè)置接口對(duì)象
private OnItemClickListener onItemClickListener;
public MainClidRecyclerViewAdapter(List<HashMap<String, Object>> mdataList, Context mContext) {
this.mdataList = mdataList;
this.mContext = mContext;
this.mLayoutInflater = mLayoutInflater.from(mContext);
}
@Override
public MainClidHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mLayoutInflater.inflate(R.layout.item_recyclerview_clidfragment, parent, false);
MainClidHolder mainClidHolder = new MainClidHolder(view);
return mainClidHolder;
}
@Override
public void onBindViewHolder(MainClidHolder holder, final int position) {
//設(shè)置數(shù)據(jù)綁定
HashMap<String, Object> itemHashMap = mdataList.get(position);
//拿到控件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(position);
}
});
holder.tvRecyclerview.setText((String)itemHashMap.get("type"));
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener=onItemClickListener;
}
@Override
public int getItemCount() {
return mdataList.size();
}
class MainClidHolder extends RecyclerView.ViewHolder {
@BindView(R.id.tv_recyclerview)
TextView tvRecyclerview;
public MainClidHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
/**
* 點(diǎn)擊事件接口
*/
public interface OnItemClickListener{
void onItemClick(int position);
}
}
現(xiàn)在我們來(lái)進(jìn)行一步一步的優(yōu)化钾菊。寫(xiě)一個(gè)BaseAdapter 使得以后所有的Recycler都用得上帅矗,用的時(shí)候直接繼承就行了。
一煞烫、基本改造浑此。
目標(biāo):數(shù)據(jù)改為泛型,布局id直接在構(gòu)造其中傳遞滞详,將數(shù)據(jù)綁定回傳給子類(lèi)凛俱,讓子類(lèi)專(zhuān)心處理這個(gè)東西。
代碼如下:
package com.lay.laykypro.adapter.ClidFragment;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
/**
* 基本改造
* @param <T>
*/
public abstract class BaseRecyclerViewAdapter<T> extends RecyclerView.Adapter<BaseRecyclerViewAdapter.ViewHolder> {
protected List<T> tList;
protected Context mContext;
protected LayoutInflater mLayoutInflater;
protected int layId;
private OnItemClickListener mOnItemClickListener;
public BaseRecyclerViewAdapter(List<T> tList, Context mContext, int layId) {
this.tList = tList;
this.mContext = mContext;
this.layId=layId;
mLayoutInflater=LayoutInflater.from(mContext);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = mLayoutInflater.inflate(layId, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(final BaseRecyclerViewAdapter.ViewHolder holder, final int position) {
convert(holder,tList.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnItemClickListener.onItemClick(position);
}
});
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.mOnItemClickListener=onItemClickListener;
}
@Override
public int getItemCount() {
return tList.size();
}
public abstract void convert(ViewHolder holder,T itemData);
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
/**
* 點(diǎn)擊事件接口
*/
public interface OnItemClickListener{
void onItemClick(int position);
}
}
二茵宪、實(shí)例嘗試
帶入上一篇博客:RecyclerView全面解析之一:基本使用和分割線的設(shè)置 - 簡(jiǎn)書(shū) http://www.reibang.com/p/cfbb0c2e9ffc的代碼進(jìn)行嘗試。
代碼如下:
package com.lay.laykypro.adapter.ClidFragment;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.lay.laykypro.R;
import java.util.HashMap;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainClidRecyclerViewAdapter extends BaseRecyclerViewAdapter<HashMap<String, Object>> {
public MainClidRecyclerViewAdapter(List<HashMap<String, Object>> hashMaps, Context mContext, int layId) {
super(hashMaps, mContext, layId);
}
@Override
public void convert(ViewHolder holder, HashMap<String, Object> itemData) {
TextView tvRecyclerView = (TextView) holder.itemView.findViewById(R.id.tv_recyclerview);
tvRecyclerView.setText((String)itemData.get("type"));
}
}
在這個(gè)地方我遇到了兩個(gè)報(bào)錯(cuò):
1.MainClidRecyclerViewAdapter 不是抽象的, 并且未覆蓋Adapter中的抽象方法onBindViewHolder(BaseRecyclerAdapter.ViewHolder,int)
2.方法不會(huì)覆蓋或?qū)崿F(xiàn)超類(lèi)型的方法
解決方法:Error:(13, 8) 錯(cuò)誤: xxx不是抽象的, 并且未覆蓋xxx中的抽象方法onBindViewHolder(BaseSimpleRecyclerAdapter.ViewHolder,int) - yql_running的博客 - CSDN博客 https://blog.csdn.net/yql_running/article/details/69054523
三瘦棋、優(yōu)化ViewHolder
之前是把所有的數(shù)據(jù)處理整理到了convert()方法中稀火,現(xiàn)在我們來(lái)優(yōu)化一下ViewHolder類(lèi)。
1.這里我們?cè)谑褂肕ap類(lèi)的時(shí)候進(jìn)行一下選擇赌朋,參考博客:
Android內(nèi)存優(yōu)化(使用SparseArray和ArrayMap代替HashMap) - 【博客地址永久遷移到】:http://zhengxiaoyong.me - CSDN博客 https://blog.csdn.net/u010687392/article/details/47809295
2.這里我們?cè)趯?xiě)setText方法的時(shí)候參考了一下:
String詳解, String和CharSequence區(qū)別, StringBuilder和StringBuffer的區(qū)別 (String系列之1) - 如果天空不死 - 博客園 http://www.cnblogs.com/skywang12345/p/string01.html
代碼如下:
public class ViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViewArray;
public ViewHolder(View itemView) {
super(itemView);
mViewArray=new SparseArray<>();
}
/**
* 通過(guò)id得到view
* @param viewId
* @param <V>
* @return
*/
public <V extends View>V getViewAtId(int viewId){
View view = mViewArray.get(viewId);
if(view==null){
view=itemView.findViewById(viewId);
mViewArray.put(viewId,view);
}
return (V)view;
}
/**
* 設(shè)置文字
* @param viewId
* @param text
* @return
*/
public ViewHolder setText(int viewId,CharSequence text){
TextView textView= getViewAtId(viewId);
textView.setText(text);
return this;
}
/**
* 通過(guò)網(wǎng)址設(shè)置圖片
* @param viewId
* @param imgUrl
* @return
*/
public ViewHolder setImageFromUrl(int viewId,String imgUrl){
ImageView imageView= getViewAtId(viewId);
Glide.with(imageView.getContext()).load(imgUrl).into(imageView);
return this;
}
/**
* 通過(guò)資源來(lái)設(shè)置圖片資源
* @param viewId
* @param resId
* @return
*/
public ViewHolder setImageFromRes(int viewId,int resId){
ImageView imageView = getViewAtId(viewId);
imageView.setImageResource(resId);
return this;
}
/**
* 設(shè)置控件透明度
* @param viewId
* @param visibility
* @return
*/
public ViewHolder setViewVisibility(int viewId,int visibility){
View view = getViewAtId(viewId);
view.setVisibility(visibility);
return this;
}
}
優(yōu)化之后凰狞, MainClidRecyclerViewAdapter 代碼如下:
package com.lay.laykypro.adapter.ClidFragment;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.lay.laykypro.R;
import java.util.HashMap;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainClidRecyclerViewAdapter extends BaseRecyclerViewAdapter<HashMap<String, Object>> {
public MainClidRecyclerViewAdapter(List<HashMap<String, Object>> hashMaps, Context mContext, int layId) {
super(hashMaps, mContext, layId);
}
@Override
public void convert(ViewHolder holder, HashMap<String, Object> itemData) {
holder.setText(R.id.tv_recyclerview,(String)itemData.get("type"));
}
}
下一步,我們來(lái)考慮多布局沛慢。
四赡若、多布局接口的實(shí)現(xiàn)
我們經(jīng)常會(huì)看到列表的呈現(xiàn)形式并不是單一形式的,也就是item的多布局团甲,之前我們不斷封裝的過(guò)程中我們應(yīng)該可以領(lǐng)悟一個(gè)基本思想逾冬,就是不變的東西我們應(yīng)該把它丟到Base類(lèi)中去,只有具體的業(yè)務(wù)邏輯才應(yīng)該放到實(shí)現(xiàn)類(lèi)中來(lái)寫(xiě)躺苦。因此身腻,借由這個(gè)基本思想我們來(lái)看看什么才是多布局功能不變的部分。
多布局的基本邏輯是通過(guò)對(duì)item的具體數(shù)據(jù)分析匹厘,以此來(lái)判斷到底應(yīng)該得到哪一個(gè)item的布局嘀趟。
在這個(gè)邏輯中,通過(guò)每一個(gè)item的數(shù)據(jù)愈诚,得到具體布局是不變的部分她按,因此,接口可得炕柔,代碼如下:
/**
* 多布局接口
* @param <T>
*/
public interface MultiTypeSupport<T>{
int getLayoutId(T item);
}
改寫(xiě)getItemViewType 方法酌泰,代碼如下:
@Override
public int getItemViewType(int position) {
if (multiTypeSupport!=null){
return multiTypeSupport.getLayoutId(tList.get(position));
}
return super.getItemViewType(position);
}
在Adapter中設(shè)置多布局:
public void setMultiTypeSupport(MultiTypeSupport<T> multiTypeSupport){
this.multiTypeSupport=multiTypeSupport;
}
改寫(xiě)onCreateViewHolder,代碼如下:
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// 多布局支持
if (multiTypeSupport != null) {
mLayoutId = viewType;//這個(gè)就是getItemViewType方法的返回值匕累,我們直接使用布局Id來(lái)做返回值宫莱,可以省略設(shè)置靜態(tài)int值。
}
View view = mLayoutInflater.inflate(mLayoutId, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
在Fragment中來(lái)寫(xiě)具體的布局邏輯哩罪,代碼如下:
mainClidRecyclerViewAdapter.setMultiTypeSupport(new BaseRecyclerViewAdapter.MultiTypeSupport<HashMap<String, Object>>() {
@Override
public int getLayoutId(HashMap<String, Object> item) {
String type = (String) item.get("type");
if(type.equals("horizontalScrollCard")){
return R.layout.item_recyclerview_clidfragment;
}else if(type.equals("header5")){
return R.layout.item_recyclerview_nofragment;
}
return 0;
}
});
最后一個(gè)問(wèn)題授霸,我們應(yīng)該怎么在convert方法中實(shí)現(xiàn)對(duì)不同的布局進(jìn)行不同的數(shù)據(jù)加載呢巡验?畢竟我們這個(gè)方法的傳入?yún)?shù)可沒(méi)有ViewType。
回答:直接通過(guò)item數(shù)據(jù)來(lái)判斷就可以了碘耳。
至此邏輯理清显设,博客結(jié)束。