Android 性能优化<九> RecyclerView替代Listview用法
- 横向滚动的ListView开源控件是不是可以不用再找了?对,你没看错!
- 瀑布流效果的开源控件是不是可以不用再找了?对,你没看错!
- 连横向滚动的GridView都不用找了!对,你没看错!
从基础使用上看,我们明显可以看出,RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:
- ViewHolder 的编写规范化了
- RecyclerView 复用 Item 的工作 Google 全帮你搞定,不再需要像 ListView 那样自己调用 setTag
- RecyclerView 需要多出一步 LayoutManager 的设置工作
initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mAdapter = new HomeAdapter(this, mDatas); //设置垂直,水平,gridview还是listview类型 mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); mRecyclerView.setAdapter(mAdapter); //设置分割线 mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this)); // 设置item动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); initEvent(); Button btn_grid=(Button) findViewById(R.id.grad_view); btn_grid.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, 4)); } }); Button btn_stoggle=(Button) findViewById(R.id.stoggle); btn_stoggle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL)); } });
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { private List<String> mDatas; private LayoutInflater mInflater; public interface OnItemClickLitener { void onItemClick(View view, int position); void onItemLongClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } public HomeAdapter(Context context, List<String> datas) { mInflater = LayoutInflater.from(context); mDatas = datas; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(mInflater.inflate( R.layout.item_layout, parent, false)); return holder; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv.setText(mDatas.get(position)); // 如果设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { holder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); removeData(pos); return false; } }); } } @Override public int getItemCount() { return mDatas.size(); } public void addData(int position) { mDatas.add(position, "Insert One"); notifyItemInserted(position); } public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); } class MyViewHolder extends ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(R.id.id_num); } } }
主要的API和方法:整体总结它的几点如下:
Adapter:包装数据集合并且为每个条目创建视图。
ViewHolder:保存用于显示每个数据条目的子View。
LayoutManager:将每个条目的视图放置于适当的位置。
ItemDecoration:在每个条目的视图的周围或上面绘制一些装饰视图(我们可以通过该方法添加分割线)。
ItemAnimator:在条目被添加、移除或者重排序时添加动画效果。
- 系统提供了几种LayoutManager的使用;
-
如何通过自定义ItemDecoration去设置分割线,或者一些你想作为分隔的drawable,注意这里
巧妙的使用了系统的listDivider属性,你可以尝试添加使用divider和dividerHeight属性。 - 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。
- 介绍了如何添加ItemClickListener与ItemLongClickListener。
1)。.Listview支持,HeaderView 和 FooterView
RecyclerView 要自己写
2).ListViewAnimations 主要大致实现方式是通过装饰者模式来扩充 Adapter ,并结合属性动画 Animator 来添加动画效果。相比之下,RecyclerView 则为我们提供了很多基本的动画 API ,如下方的增删移改
3).局部刷新
朋友圈点赞,点赞只是更新当前点赞的Item,并不需要每个 Item 都更新。
public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
RecyclerView.Adapter 则我们提供了
notifyItemChanged 用于更新单个 Item View 的刷新,我们可以省去自己写局部更新的工作。
public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
public final void notifyItemInserted(int position),这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。
public final void notifyItemMoved(int fromPosition, int toPosition),这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新
public final void notifyItemRangeInserted(int positionStart, int itemCount),显然是批量添加。
public final void notifyItemRemoved(int position),第position个被删除的时候刷新,同样会有动画。
public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。
嵌套滚动机制
空数据处理
ListView 提供了 setEmptyView 这个 API 来让我们处理 Adapter 中数据为空的情况,只需轻轻一 set 就能搞定一切。代码设置和效果如下
mListView = (ListView) findViewById(R.id.lv_show_tidy); mListView.setEmptyView();
- 横向滚动的ListView开源控件是不是可以不用再找了?对,你没看错!
- 瀑布流效果的开源控件是不是可以不用再找了?对,你没看错!
- 连横向滚动的GridView都不用找了!对,你没看错!
从基础使用上看,我们明显可以看出,RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:
- ViewHolder 的编写规范化了
- RecyclerView 复用 Item 的工作 Google 全帮你搞定,不再需要像 ListView 那样自己调用 setTag
- RecyclerView 需要多出一步 LayoutManager 的设置工作
initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mAdapter = new HomeAdapter(this, mDatas); //设置垂直,水平,gridview还是listview类型 mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); mRecyclerView.setAdapter(mAdapter); //设置分割线 mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this)); // 设置item动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); initEvent(); Button btn_grid=(Button) findViewById(R.id.grad_view); btn_grid.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, 4)); } }); Button btn_stoggle=(Button) findViewById(R.id.stoggle); btn_stoggle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL)); } });
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { private List<String> mDatas; private LayoutInflater mInflater; public interface OnItemClickLitener { void onItemClick(View view, int position); void onItemLongClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } public HomeAdapter(Context context, List<String> datas) { mInflater = LayoutInflater.from(context); mDatas = datas; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(mInflater.inflate( R.layout.item_layout, parent, false)); return holder; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv.setText(mDatas.get(position)); // 如果设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { holder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); removeData(pos); return false; } }); } } @Override public int getItemCount() { return mDatas.size(); } public void addData(int position) { mDatas.add(position, "Insert One"); notifyItemInserted(position); } public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); } class MyViewHolder extends ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(R.id.id_num); } } }
主要的API和方法:整体总结它的几点如下:
Adapter:包装数据集合并且为每个条目创建视图。
ViewHolder:保存用于显示每个数据条目的子View。
LayoutManager:将每个条目的视图放置于适当的位置。
ItemDecoration:在每个条目的视图的周围或上面绘制一些装饰视图(我们可以通过该方法添加分割线)。
ItemAnimator:在条目被添加、移除或者重排序时添加动画效果。
- 系统提供了几种LayoutManager的使用;
-
如何通过自定义ItemDecoration去设置分割线,或者一些你想作为分隔的drawable,注意这里
巧妙的使用了系统的listDivider属性,你可以尝试添加使用divider和dividerHeight属性。 - 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。
- 介绍了如何添加ItemClickListener与ItemLongClickListener。
1)。.Listview支持,HeaderView 和 FooterView
RecyclerView 要自己写
2).ListViewAnimations 主要大致实现方式是通过装饰者模式来扩充 Adapter ,并结合属性动画 Animator 来添加动画效果。相比之下,RecyclerView 则为我们提供了很多基本的动画 API ,如下方的增删移改
3).局部刷新
朋友圈点赞,点赞只是更新当前点赞的Item,并不需要每个 Item 都更新。
public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
RecyclerView.Adapter 则我们提供了
notifyItemChanged 用于更新单个 Item View 的刷新,我们可以省去自己写局部更新的工作。
public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。
public final void notifyItemInserted(int position),这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。
public final void notifyItemMoved(int fromPosition, int toPosition),这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新
public final void notifyItemRangeInserted(int positionStart, int itemCount),显然是批量添加。
public final void notifyItemRemoved(int position),第position个被删除的时候刷新,同样会有动画。
public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。
嵌套滚动机制
空数据处理
ListView 提供了 setEmptyView 这个 API 来让我们处理 Adapter 中数据为空的情况,只需轻轻一 set 就能搞定一切。代码设置和效果如下
mListView = (ListView) findViewById(R.id.lv_show_tidy); mListView.setEmptyView();