共计 6783 个字符,预计需要花费 17 分钟才能阅读完成。
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();
@Override
protected 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。
@Override
protected 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 零根底入门教程视频参考