昨天写了一篇「还在用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或者一起共同将它完毕的更完好。送大家一句我非常喜欢的话:不分享谁与你共享呢?
源代码地址:传送门