Android面试题汇总-RecyclerView、Fragment、WebView、性能优化等

一、RecyclerView

1、RecyclerView的多级缓存机制,每一级缓存具体作用是什么,分别在什么场景下会用到哪些缓存

RecyclerView的多级缓存机制是为了提高滚动和数据更新的效率而设计的。每一级缓存都有其特定的作用和使用场景。以下是各级缓存的作用和它们的使用场景:

  • 一级缓存:mAttachedScrap 和 mChangedScrap
  • 二级缓存:mCachedViews
  • 三级缓存:ViewCacheExtension
  • 四级缓存:RecycledViewPool
  1. mAttachedScrap:
    • 作用:这是一个ArrayList,用于存储暂时分离的子视图(Scrap view)。这些视图可以重复使用而不需要与RecyclerView完全分离。如果视图不需要重新绑定数据,就不会进行修改。
    • 使用场景:在布局期间和数据更新时,这个缓存会被使用。
  2. mChangedScrap:
    • 作用:类似于mAttachedScrap,但它存放的是发生变化的ViewHolder。如果使用到了这里的缓存的ViewHolder,需要重新走Adapter的绑定方法。
    • 使用场景:在数据有局部更新时使用。
  3. mCachedViews:
    • 作用:这是一个有容量限制的ArrayList,默认大小为2。它存放的是已经从RecyclerView中移除的视图,但ViewHolder仍然保存着之前的信息,如位置和绑定的数据等。
    • 使用场景:在滚动过程中和预取(prefetch)时使用。
  4. RecycledViewPool:
    • 作用:这是一个全局的缓存池,可以跨多个RecyclerView共享。它用于存储不再需要的ViewHolder,任何绑定过的痕迹都没有了。当需要新的item时,可以从这个池中获取,并进行重用。
    • 使用场景:在Item被移除、有更新或滚动过程中使用。
  5. ViewCacheExtension:
    • 作用:这是一个开发者可以自定义的缓存层级。官方没有默认实现,它允许开发者根据自己的需求来缓存ViewHolder。
    • 使用场景:取决于开发者如何实现它。

通过有效地管理ViewHolder的缓存和重用,RecyclerView的多级缓存机制极大地提高了处理大量数据集时的性能和效率。

2、RecyclerView的滑动回收复用机制

RecyclerView的滑动回收复用机制是其核心功能之一,它允许应用高效地处理大量的数据集。这个机制确保了用户界面的流畅滚动,即使是在数据集非常大的情况下。

  1. 滑动和回收:
    • 当用户滑动屏幕时,RecyclerView会检测到哪些项(item views)不再可见,并将这些项的ViewHolder回收到缓存中。这个过程称为回收(Recycling)。
    • 回收的ViewHolder会被存放在一个叫做mCachedViews的缓存列表中。这个列表有一个固定的大小,当达到上限时,最早回收的ViewHolder会被移除并放入另一个缓存池,即RecycledViewPool
  2. 复用:
    • 当新的项需要显示在屏幕上时,RecyclerView会首先尝试从mCachedViews中复用ViewHolder。如果找到了合适的ViewHolder,就会直接使用它,而不需要重新创建一个新的。
    • 如果mCachedViews中没有可用的ViewHolder,RecyclerView会转而从RecycledViewPool中寻找。RecycledViewPool是一个更大的缓存池,可以跨多个RecyclerView实例共享。
  3. 绑定数据:
    • 一旦找到了一个可复用的ViewHolder,RecyclerView会通过调用Adapter的onBindViewHolder方法来绑定新的数据。这个过程称为绑定(Binding)。
    • 绑定数据是必要的步骤,因为虽然ViewHolder可能是复用的,但显示的数据需要是当前项的数据。
  4. LayoutManager的角色:
    • LayoutManager负责决定屏幕上项的布局方式。它也参与回收和复用的过程,因为它知道哪些项不再可见,以及何时需要新的项来填充屏幕。
  5. 优化:
    • RecyclerView还包含了其他优化措施,比如预取(Prefetching),它会在后台线程中提前绑定数据,以减少滚动时的延迟。

通过这种方式,RecyclerView能够快速地回收和复用ViewHolder,从而实现高效的滚动性能。这个机制是Android开发中非常重要的优化手段,它使得即使是数据量巨大的列表也能够流畅地滚动。

3、RecyclerView的刷新回收复用机制

RecyclerView的刷新回收复用机制是其核心特性之一,它允许应用程序高效地处理和显示大量数据。这个机制主要包括以下几个步骤:

  1. 刷新(Refresh):
    • 当数据集发生变化时,例如通过notifyDataSetChanged()方法,RecyclerView会被通知需要刷新。
    • 刷新操作会导致RecyclerView重新绑定和布局视图,但尽可能地利用已有的ViewHolder进行数据绑定,以避免不必要的视图创建。
  2. 回收(Recycle):
    • 当滑动RecyclerView时,屏幕上不再可见的视图会被回收到缓存中。
    • 回收的视图不会立即被销毁,而是存放在缓存中,等待复用。
  3. 复用(Reuse):
    • 当需要显示新的数据项时,RecyclerView会首先尝试从缓存中查找可复用的ViewHolder。
    • 如果缓存中有合适的ViewHolder,就会直接使用它并绑定新的数据,而不是创建一个新的ViewHolder。

RecyclerView的回收复用机制涉及到几个关键的缓存结构:

  • mCachedViews: 这是一个临时缓存,用于存放最近被回收的ViewHolder。它的默认大小为2,但可以根据需要调整。
  • RecycledViewPool: 这是一个更大的缓存池,用于存放不同类型的ViewHolder。它允许不同的RecyclerView共享ViewHolder,从而提高复用效率。
  • ViewCacheExtension: 这是一个可选的缓存扩展点,开发者可以自定义缓存策略,以适应特定的复用需求。

在刷新过程中,RecyclerView会尽量复用已有的ViewHolder,减少创建和销毁视图的开销,从而提高性能和流畅度。这个机制确保了即使在数据频繁更新的情况下,用户界面也能保持流畅的滚动体验。

4、RecyclerView 为什么要预布局

RecyclerView 的预布局用于 Item 动画中,也叫做预测动画。其用于当 Item 项进行变化时执行的一次布局过程(如添加或删除 Item 项),使 ItemAnimator 体验更加友好。

考虑以下 Item 项删除场景,屏幕内的 RecyclerView 列表包含两个 Item 项:item1 和 item2。当删除 item2 时,item3 从底部平滑出现在 item2 的位置:

+-------+                       +-------+
|       | <-----+               |       | <-----+
| item1 |       |               | item1 |       |
|       |       |               |       |       |
+-------+     screen   ---->    +-------+     screen
|       |       |               |       |       |
| item2 |       |               | item3 |       |
|       | <-----+               |       | <-----+
+-------+                       +-------+

上述效果是如何实现的呢?我们知道 RecyclerView 只会布局屏幕内可见的 Item,对于屏幕外的 item3,如何知道其要运行的动画轨迹呢?要形成轨迹,至少需要知道起始点,而 item3 的终点位置是很明确的,也就是被删除的 item2 位置。那起点是如何确定的呢?

对于这种情况,RecyclerView 会进行两次布局:

  1. 第一次被称为 pre-layout,也就是预布局。在这一阶段,RecyclerView 将不可见的 item3 也加载进布局内,得到 [item1, item2, item3] 的布局信息。
  2. 之后再执行一次 post-layout,得到 [item1, item3] 的布局信息。比对两次 item3 的布局信息,也就确定了 item3 的动画轨迹了。

这个预布局的过程使得 ItemAnimator 能够更好地执行动画,提升用户体验。

5、ListView 与 RecyclerView区别

ListView 和 RecyclerView 都是 Android 中用于展示列表数据的组件,但它们在设计和功能上有一些关键的区别。以下是 ListView 和 RecyclerView 的主要区别:

  1. 缓存机制:
    • ListView 有一个基本的缓存机制,它通过重用屏幕外的视图来优化性能。
    • RecyclerView 引入了一个更复杂的缓存系统,包括四级缓存,使得视图的重用和数据更新更加高效。
  2. 布局管理:
    • ListView 默认只支持垂直滚动的列表。
    • RecyclerView 通过 LayoutManager 支持更多样化的布局,如线性布局、网格布局和瀑布流布局。
  3. ViewHolder 的使用:
    • 在 ListView 中,开发者需要自定义 ViewHolder 并使用 setTag()getTag() 方法来优化视图的重用。
    • RecyclerView 有一个规范化的 ViewHolder 使用方式,不需要 setTag()getTag() 方法。
  4. 数据更新:
    • ListView 在数据更新时通常使用 notifyDataSetChanged() 方法,这会导致整个列表刷新。
    • RecyclerView 允许局部数据更新,如 notifyItemChanged(),这样可以提高性能和用户体验。
  5. 动画和装饰:
    • RecyclerView 提供了丰富的动画 API 和装饰功能,可以轻松添加分隔线、动画等。
    • ListView 的动画和装饰功能较为有限。
  6. 触摸反馈:
    • RecyclerView 通过 ItemTouchHelper 支持拖动和滑动操作,这在 ListView 中不是原生支持的。
  7. 嵌套滚动:
    • RecyclerView 实现了嵌套滚动机制,可以与其他滚动容器(如 ViewPager)更好地协同工作。
    • ListView 没有实现嵌套滚动机制。
6、RecyclerView性能优化

当涉及到 Android 中的列表展示时,RecyclerView 是一个常用的组件。它的性能对用户体验至关重要。

数据优化

  1. 分页加载和数据缓存
    • 对于远程数据,建议进行分页加载,并对拉取的数据进行缓存。这样可以提高二次加载速度。
    • 使用 DiffUtil 来局部刷新新增或删除的数据,而不是全局刷新整个列表。DiffUtil 是 Android Support 库中的一个工具类,用于判断新旧数据的差异,从而进行局部刷新。
  2. 分离数据处理和视图绑定
    • RecyclerView.AdapteronBindViewHolder 方法中,应该只是将数据设置到视图中,而不应进行耗时的业务处理。例如,避免在此方法中进行日期比较和格式化操作。

布局优化

  1. 减少过度绘制
    • 减少布局层级,可以考虑使用自定义 View 来减少层级,或者更合理地设置布局来减少层级。
    • 注意:目前不推荐在 RecyclerView 中使用 ConstraintLayout,因为在某些版本中性能表现不佳。
  2. 减少 XML 文件的 Inflate 时间
    • XML 文件包括 layoutdrawable 的 XML,它们的 Inflate 操作是耗时的 I/O 操作。
    • 可以考虑使用代码生成布局,即通过 new View() 的方式来创建布局。
  3. 减少 View 对象的创建
    • 复杂的列表项可能包含大量的 View,而 View 的创建会消耗时间。因此,尽量简化 ItemView,设计共用的部分,减少 View 的构造和嵌套。
  4. 设置高度固定
    • 如果列表项的高度是固定的,可以使用 RecyclerView.setHasFixedSize(true) 来避免不必要的 requestLayout 操作。
  5. 共用 RecycledViewPool
    • 在嵌套的 RecyclerView 中,如果子 RecyclerView 具有相同的适配器,可以设置共用一个 RecycledViewPool
    • 注意:如果使用的是 LinearLayoutManager 或其子类,需要手动开启这个特性。

二、Fragment

1、Fragment的生命周期(结合Activity的生命周期)

在 Android 开发中,理解 Fragment 的生命周期及其与 Activity 生命周期的关系是非常重要的。Fragment 的生命周期与 Activity 紧密相关,但也有其独特的回调方法。以下是 Fragment 生命周期的一个概述,结合了 Activity 的生命周期:

  1. onAttach():
    • 当 Fragment 与 Activity 关联时调用。
    • 这是 Fragment 生命周期的第一个回调。
  2. onCreate():
    • 用于进行 Fragment 的初始创建。
    • 在这里可以初始化除了视图以外的组件。
  3. onCreateView():
    • 创建并返回与 Fragment 关联的视图层次结构。
    • 这是设置 Fragment 布局的地方。
  4. onActivityCreated():
    • 当 Activity 完成 onCreate() 方法后调用。
    • 可以在这里进行最终的初始化,如检索视图和恢复状态。
  5. onStart():
    • 当 Fragment 对用户可见时调用。
    • Activity 的 onStart() 也会被调用。
  6. onResume():
    • 当 Fragment 开始与用户交互时调用。
    • Activity 的 onResume() 也会被调用。
  7. onPause():
    • 当 Fragment 不再与用户交互时调用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JPC客栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值