RecyclerView.Adapter優化了嗎?
阿新 • • 發佈:2019-01-09
昨天寫了一篇「還在用ListView?」講的內容是RecyclerView的使用技巧以及一些常用的開源庫,有朋友反饋“我已經在用recyclerview了”,那麼如何讓它更好用呢?此時我想到了優化RecyclerView.Adapter,因為在RecyclerView還沒出來之前我就寫過一篇「ListView之Adapter優化」,通過這篇文章的優化思路可以在原來的程式碼上修改部分程式碼用在優化RecyclerView.Adapter上,一如既往的好用。
本次主要講兩個方面的優化
- 精簡程式碼
- 擴充套件功能
精簡程式碼
正常沒優化的寫法:
public class DefAdpater extends RecyclerView.Adapter<DefAdpater.ViewHolder> {
private final List<Status> sampleData = DataServer.getSampleData();
private Context mContext;
public DefAdpater(Context context) {
mContext = context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext()).inflate(R.layout.tweet, parent, false);
return new ViewHolder(item);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Status status = sampleData.get(position);
holder.name.setText(status.getUserName());
holder.text.setText(status.getText());
holder.date.setText(status.getCreatedAt());
Picasso.with(mContext).load(status.getUserAvatar()).into(holder.avatar);
holder.rt.setVisibility(status.isRetweet() ? View.VISIBLE : View.GONE);
}
@Override
public int getItemCount() {
return sampleData.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView avatar;
private ImageView rt;
private TextView name;
private TextView date;
private TextView text;
public ViewHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.tweetText);
name = (TextView) itemView.findViewById(R.id.tweetName);
date = (TextView) itemView.findViewById(R.id.tweetDate);
avatar = (ImageView) itemView.findViewById(R.id.tweetAvatar);
rt = (ImageView) itemView.findViewById(R.id.tweetRT);
}
}
}
優化後,是這樣的:
public class QuickAdapter extends BaseQuickAdapter<Status> {
public QuickAdapter(Context context) {
super(context, R.layout.tweet, DataServer.getSampleData());
}
@Override
protected void convert(BaseAdapterHelper helper, Status item) {
helper.setText(R.id.tweetName, item.getUserName())
.setText(R.id.tweetText, item.getText())
.setText(R.id.tweetDate, item.getCreatedAt())
.setImageUrl(R.id.tweetAvatar, item.getUserAvatar())
.setVisible(R.id.tweetRT, item.isRetweet())
.linkify(R.id.tweetText);
}
}
優化前和優化後的程式碼量是3:1的比例!
我的天啦!太不可思議了!
現在來分析,如何優化的?(帶著問題學習)
思路:
找到重複部分程式碼,抽取到基類,非重複部分用抽象方法代替,具體讓子類實現。
說了思路在看看具體程式碼BaseQuickAdapter裡面怎麼寫的:
@Override
public int getItemCount() {
return data.size();
}
@Override
public BaseAdapterHelper onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext()).inflate(layoutResId, parent, false);
return new BaseViewHolder(context, item);
}
@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {
convert(holder, data.get(position));
}
protected abstract void convert(BaseViewHolder helper, T item);
接下來再看看BaseViewHolder怎麼寫的:
public class BaseViewHolder extends RecyclerView.ViewHolder {
private final SparseArray<View> views;
private final Context context;
private View convertView;
protected BaseViewHolder(Context context, View view) {
super(view);
this.context = context;
this.views = new SparseArray<View>();
convertView = view;
}
protected <T extends View> T retrieveView(int viewId) {
View view = views.get(viewId);
if (view == null) {
view = convertView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
public BaseViewHolder setText(int viewId, CharSequence value) {
TextView view = retrieveView(viewId);
view.setText(value);
return this;
}
public BaseViewHolder setImageUrl(int viewId, String imageUrl) {
ImageView view = retrieveView(viewId);
Picasso.with(context).load(imageUrl).into(view);
return this;
}
public BaseViewHolder setVisible(int viewId, boolean visible) {
View view = retrieveView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
public BaseViewHolder linkify(int viewId) {
TextView view = retrieveView(viewId);
Linkify.addLinks(view, Linkify.ALL);
return this;
}
//此處省略若干常用賦值常用方法
}
利用SparseArray來做快取,把常用方法全部寫好,從而避免冗餘程式碼。
擴充套件功能
大家都知道RecyclerView沒有ItemClick方法,可以在上面提過的BaseQuickAdapter裡面新增ItemClick,可以這樣:
網上有很多寫法都是在
onBindViewHolder
裡面寫,功能是可以實現但是會導致頻繁建立,應該在onCreateViewHolder()
中每次為新建的 View 設定一次就行了。
private OnRecyclerViewItemClickListener onRecyclerViewItemClickListener;
public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener onRecyclerViewItemClickListener) {
this.onRecyclerViewItemClickListener = onRecyclerViewItemClickListener;
}
public interface OnRecyclerViewItemClickListener {
public void onItemClick(View view, int position);
}
@Override
public void onCreateViewHolder(ViewGroup parent, int viewType) {
// init ViewHolder ...
if (onRecyclerViewItemClickListener != null) {
holder.getView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onRecyclerViewItemClickListener.onItemClick(v, holder.getLayoutPosition());
}
});
}
}
還可以新增一些常用的方法如:
public void remove(int position) {
data.remove(position);
notifyItemRemoved(position);
}
public void add(int position, T item) {
data.add(position, item);
notifyItemInserted(position);
}
程式碼我已經上傳到GitHub上了,有興趣的同學Star或者一起共同將它完成的更完善!送大家一句我非常喜歡的話:不分享誰與你共享呢?
原始碼地址:傳送門