RecyclerView理论应用

用 RecyclerView 做出一个列表。显示测试数据。

这个示例会分为以下几个步骤:

  • 确定数据。这里用的是模仿数据。
  • 设计UI和表现形式。
  • 编写 layout 与适配器。

模仿数据

巧妇难为无米之炊,模仿数据就是模仿需要。

新建一个类 DataTest,设计 4 个属性。

public class DataTest {    private String timezone;    private int number;    private int personCount;    private int count;    public DataTest(String timezone, int number, int personCount, int count) {        this.timezone = timezone;        this.number = number;        this.personCount = personCount;        this.count = count;    }// getter setter...}

设计 item 的布局

设计UI,在一行里显示 4 个属性值。item 用的是 item_recy2.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="horizontal">    <TextView        android:id="@+id/tv1"        style="@style/RePage2Header"        android:layout_marginEnd="@dimen/re_2_half_gap" />    <TextView        android:id="@+id/tv2"        style="@style/RePage2Header"        android:layout_marginStart="@dimen/re_2_half_gap"        android:layout_marginEnd="@dimen/re_2_half_gap" />    <TextView        android:id="@+id/tv3"        style="@style/RePage2Header"        android:layout_marginStart="@dimen/re_2_half_gap"        android:layout_marginEnd="@dimen/re_2_half_gap" />    <TextView        android:id="@+id/tv4"        style="@style/RePage2Header"        android:layout_marginStart="@dimen/re_2_half_gap" /></LinearLayout>

筹备色彩,尺寸等资源

相干的style和色彩,尺寸配置文件,在res/values目录下。

style文件style.xml

<style name="RePage2Header">    <item name="android:layout_width">0dp</item>    <item name="android:layout_height">40dp</item>    <item name="android:layout_weight">2</item>    <item name="android:textColor">#ffffff</item>    <item name="android:gravity">center</item>    <item name="android:background">@color/rePage2Item</item></style>

咱们给 layout 里的每个TextView都设置了 layout_width 为 0dp。是为了应用 layout_weight 属性。 让它们 4 个 TextView 按比例宰割父 View 的宽度。

这里的宰割用到了LinearLayout的宰割占比个性。

色彩配置文件color.xml,增加如下色彩设置。

<color name="rePage2Item">#082941</color>

尺寸配置dimens.xml。

<dimen name="re_2_gap">4dp</dimen><dimen name="re_2_half_gap">2dp</dimen>
设计 ViewHolder

资源文件和 layout 筹备得当,开始写对应的 viewHolder。这里也是把 VH 类和 Adapter 类放在 activity 类外面。

private class VH extends RecyclerView.ViewHolder {    TextView tv1;    TextView tv2;    TextView tv3;    TextView tv4;    public VH(@NonNull View itemView) {        super(itemView);        tv1 = itemView.findViewById(R.id.tv1);        tv2 = itemView.findViewById(R.id.tv2);        tv3 = itemView.findViewById(R.id.tv3);        tv4 = itemView.findViewById(R.id.tv4);    }}
设计 Adapter 类

适配器 Adapter 类。

private class Adapter extends RecyclerView.Adapter<VH> {    private List<DataTest> dataList = new ArrayList<>();    public Adapter() {    }    public void setDataList(List<DataTest> dataList) {        this.dataList = dataList; // 最好进行判空操作        notifyDataSetChanged();    }    @NonNull    @Override    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {        return new VH(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recy2, parent, false));    }    @Override    public void onBindViewHolder(@NonNull VH holder, int position) {        DataTest dataTest = dataList.get(position);        holder.tv1.setText(dataTest.getTimezone());        holder.tv2.setText(String.valueOf(dataTest.getNumber()));        holder.tv3.setText(String.valueOf(dataTest.getPersonCount()));        holder.tv4.setText(String.valueOf(dataTest.getCount()));    }    @Override    public int getItemCount() {        return dataList.size();    }}
配置 RecyclerView

设置 recyclerview。

// 在activity或者fragment里private Adapter mAdapter = new Adapter();@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.act_recy_2);    RecyclerView recyclerView = findViewById(R.id.re_view);    recyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));    recyclerView.setAdapter(mAdapter);    mAdapter.setDataList(genDataTestList());    recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {        @Override        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {            super.getItemOffsets(outRect, view, parent, state);            outRect.top = getResources().getDimensionPixelOffset(R.dimen.re_2_gap);        }    });}// 生成模仿数据private List<DataTest> genDataTestList() {    List<DataTest> list = new ArrayList<>();    for (int i = 1; i <= 60; i++) {        DataTest d = new DataTest("时区" + i, i, i, i);        list.add(d);    }    return list;}

在 onCreate 办法中配置 recyclerView。 recyclerView.addItemDecoration 办法是给 item 设置距离款式。 getItemOffsets 能够设置子项的间距。这里给子项底部一个间距值。具体数值设置在 dimen 中。 genDataTestList() 是生成模仿的数据。

应用 include 批改 layout

有的敌人问:表头和item的构造是一样的,能够复用吗?

其实是能够的。咱们能够在layout中应用include标签,把另一个layout文件“蕴含”进来。 复制act_recy_2.xml粘贴失去act_recy_2_include.xml,把原来的表头的 LinearLayout 改成 include。

<include layout="@layout/item_recy2" />

给 include 设定 layout,即咱们定义的 item 的布局item_recy2。 当咱们想增加个margin-top的时候,比方这样

<include    android:layout_marginTop="4dp"    layout="@layout/item_recy2" />

as会弹出正告:

Layout parameter layout_marginTop ignored unless both layout_width and layout_height are also specified on tag

也就是在 include 标签中,如果要设置其余属性,须要先设置 layout_width 和 layout_height。

批改一下,再加个 id,变成这样。

<include    android:id="@+id/header"    layout="@layout/item_recy2"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginTop="4dp" />

让Activity应用这个layout。批改一下RecyclerViewDemo2Act。

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.act_recy_2_include);    initHeader();    // 配置RecyclerView的局部}private void initHeader() {    View header = findViewById(R.id.header);    TextView tv1 = header.findViewById(R.id.tv1);    tv1.setText("时区");    TextView tv2 = header.findViewById(R.id.tv2);    tv2.setText("序号");    TextView tv3 = header.findViewById(R.id.tv3);    tv3.setText("人员");    TextView tv4 = header.findViewById(R.id.tv4);    tv4.setText("数量");}

咱们增加了一个办法 initHeader()。外面先把 header 找到,通过 header 找到它的子 view,也就是那4个TextView。 别离设置文字即可。

RecyclerView 相干面试题

1. RecyclerView第一次layout时,会产生预布局pre-layout吗?

第一次布局时,并不会触发pre-layout。pre-layout只会在每次notify change时才会被触发,目标是通过saveOldPosition办法将屏幕中各地位上的ViewHolder的坐标记录下来,并在从新布局之后,通过比照实现Item的动画成果。

2. ViewHolder何时被缓存到RecycledViewPool中?

次要有以下2种状况:

  • 当ItemView被滑动出屏幕时,并且CachedView已满,则ViewHolder会被缓存到RecycledViewPool中
  • 当数据产生变动时,执行完disappearrance的ViewHolder会被缓存到RecycledViewPool中

3. CachedView 和 RecycledViewPool 的关系

当一个ItemView被滑动滚出屏幕之后,默认会先被保留在CachedView中。CachedView的默认大小为2,能够通过 setItemViewCacheSize 办法批改它的值。

当CachedView已满后,后续有新的ItemView从屏幕内滑出时,会迫使CachedView依据FIFO规定,将之前的缓存的ViewHolder转移到RecycledViewPool中.

RecycledViewPool默认大小为5,能够通过以下形式批改RecycledViewPool的缓存大小:

RecyclerView.getRecycledViewPool().setMaxRecycledViews(int viewType, int max);

4. CachedView 和 RecycledViewPool 两者区别

缓存到CachedView中的ViewHolder并不会清理相干信息(比方position、state等),因而刚移出屏幕的ViewHolder,再次被移回屏幕时,只有从CachedView中查找并显示即可,不须要从新绑定(bindViewHolder)。

而缓存到RecycledViewPool中的ViewHolder会被清理状态和地位信息,因而从RecycledViewPool查找到ViewHolder,须要从新调用bindViewHolder绑定数据。

5. 你是从哪些方面优化RecyclerView的?

次要能够从以下几个方面对 RecyclerView 进行优化:

  • 尽量将简单的数据处理操作放到异步中实现。RecyclerView 须要展现的数据常常是从远端服务器上申请获取,然而在网络申请拿到数据之后,须要将数据做扁平化操作,尽量将最优质的数据格式返回给UI线程。
  • 优化 RecyclerView 的布局,防止将其与 ConstraintLayout 应用
  • 针对疾速滑动事件,能够应用 addOnScrollListener 增加对疾速滑动的监听,当用户疾速滑动时,进行加载数据操作。
  • 如果 ItemView 的高度固定,能够应用 setHasFixSize(true)。这样 RecyclerView 在 onMeasure 阶段能够间接计算出高度,不须要屡次计算子 ItemView 的高度,这种状况对于垂直 RecyclerView 中嵌套横向 RecyclerView 成果十分显著。
  • 当 UI 是 Tab feed 流时,能够思考应用 RecycledViewPool 来实现多个 RecyclerView 的缓存共享。

Android零根底入门教程视频参考