RecyclerView使用方法举例(1)

  RecyclerView是在Android L中新加入的ViewGroup,可以通过Support Library在更早的版本的Android上使用。文档中对RecyclerView的概述只有一行“A flexible view for providing a limited window into a large data set”,Google希望用RecyclerView来替代之前的ListView和GridView。

  在ListView和GridView中,数据的获取和显示等功能是紧耦合的,所以用了两个类来分别实现列表和网格的显示。而RecyclerView只关心“Recycle”,至于里面的各个item如何摆放、列表如何显示,统统委托给了其他类来负责。这使得RecyclerView在带来更加灵活丰富的功能的同时,使用上也变得更加复杂,很多ListView和GridView中集成的功能,都需要手动实现。使用RecyclerView,通常离不开一下几个类:

  • Adapter:和ListView和GridView类似,用于包装数据,并负责单个item的创建。Adapter通过ViewHolder获得当前item中需要更新的View。
  • ViewHolder:持有当前item的所有子View,RecyclerView的Adapter强制使用View Holder的模式。
  • LayoutManager:负责摆放item。
  • ItemDecoration:在item周围绘制装饰,如分隔线。
  • ItemAnimator:在对item进行添加、移除、重新排列操作时添加动画效果。

  下面通过一个例子介绍RecyclerView的简单使用方法。这个例子从TMDb上获取若干流行电影的信息,使用RecyclerView以网格的形式显示出来。

1. 原始数据获取

  例子中使用的数据来自TMDb,详情请参考Retrofit使用方法举例。后续内容可以接着Retrofit使用方法举例中提供的例子继续进行。

2. 添加Layout

2.1. 添加RecyclerView

  使用Support Library版本的RecyclerView可以获得向前兼容。

  完整文件在这里

2.2. 添加Item

  下面定义RecyclerView中每一个item的布局,包含一个用于显示海报的ImageView和一个用于显示电影名称的TextView。

  完整文件在这里

3. 实现Adapter

  前面定义类item的布局,但RecyclerView还不知道如何把数据填到item里面去,这是Adapter的工作。RecyclerView的Adapter强制使用ViewHolder的模式,由ViewHolder持有item中的所有子View。定义 MovieAdapter 如下,它继承了 RecyclerView.Adapter<MovieAdapter.ViewHolder> ,包含一个Movie的List作为数据集:

  要实现 MovieAdapter ,需要实现 MovieAdapter.ViewHolder ,并重写 onCreateViewHolder() 、 onBindViewHolder() 和 getItemCount() 三个方法。

3.1. 实现ViewHolder

  下面来实现 MovieAdapter.ViewHolder ,这里以内部类的形式实现:

ViewHolder 构造器中,在 itemView 下面找到用于显示海报的 movie_poster 和 movie_title ,保存为成员变量。

3.2. 重写onCreateViewHolder()

   onCreateViewHolder() 用于创建单个item,获取LayoutInflater后,inflate之前定义的item的布局 item_movie ,并以此实例化ViewHolder。

inflater.inflate(R.layout.item_movie, parent, false) 中的最后一个参数 false 为”attachToRoot“,如果为true,由此inflate得到的View会自动加到parent中,作为parent的子View。

3.3. 重写onBindViewHolder()

   onBindViewHolder() 负责将数据填入item。

position 从数据集中取出对应元素,填入ViewHolder的对应View中。这里将电影名称填入 mTitle ,并使用Picasso将海报图片下载并加载到 mPoster 。Picasso是一个Android上的图片下载和缓存库,使用方法十分简单,这里从 url 下载图片并显示在 holder.mPoster 中,在下载完成之前,使用 R.drawable.placeholder_poster_white 显示在 holder.mPoster 里作为占位符,如果下载失败,依然显示 R.drawable.placeholder_poster_white 。注意从TMDb得到的海报链接是一个key,需要经过处理得到完整链接,详情可以参考这里的“Image Languages”一节。

3.4. 重写getItemCount()

   getItemCount() 用于返回当前数据集中数据元素的个数。这里使用的是List,获取其长度十分简单。

  以上完整文件可以参考这里

4. 设置RecyclerView

  首先找到RecyclerView:

  然后进行设置:

首先将 mMovies 传入MovieAdapter作为数据集,并使用 recyclerView.setAdapter() 将 mMovieAdapter 作为RecyclerView的Adapter。然后设置布局,这里使用 GridLayoutManager 获得网格的布局, new GridLayoutManager(getContext(), 2) 中的 2 表示有两列,使用 recyclerView.setLayoutManager() 配置到RecyclerView。最后 recyclerView.setHasFixedSize(true) 表示RecyclerView中的每一个item都有固定的尺寸(RecyclerView支持显示各种不同尺寸的item),如果每一个item大小都一样,可借此来优化显示效率。

  完整文件在这里

5. 通知数据更新

  前面 mMovieAdapter = new MovieAdapter(mMovies); 的时候, mMovies 中可能还是空的,在从TMDb获得电影数据,填充 mMovies 后,需要通知MovieAdapter有数据更新。

mMovies 初始是空的,这里将新数据加入,最后使用 notifyItemInserted(0) 通知 mMovieAdapter 在位置0添加了数据。RecyclerView.Adapter还提供了很多其他的方法用于通知数据更新,可以参考这里,其中 notifyDataSetChanged() 最为万能,不需要任何参数,但效率也最低,应作为最后手段。

  完整文件在这里

6. 完整代码

  完整代码可以在这里找到。运行效果如图1所示。

 图1

图1