我显示设备的联系人列表。在我的Android版本9的三星Galaxy S8中,当我第一次滚动recyclerView时,它并不平滑且有点滞后。但是随后它开始非常流畅地滚动。如果我使用“后退”按钮关闭该应用程序并再次启动该应用程序,它将再次平滑滚动,但是如果我从最近的历史记录中销毁了该应用程序的实例,然后再次启动该应用程序,则它并不平滑且仅在第一次滚动时出现了一些滞后。(我已经在Google Pixel2中进行了测试,当黄油含量较低时,我会感到与我解释的相同。)
这是Galaxy s8中该问题的录制屏幕:https ://drive.google.com/file/d/1szfF1oKEYZK3LIqQHC-MsapRxdJ85bFy/view ? usp = sharing
我尽可能优化了recyclerView适配器,看来问题与我的适配器无关。您可以在此处检查源代码:https : //github.com/Ali-Rezaei/Contacts
我有一个自定义的CoordinatorLayout.Behavior来隐藏/显示AppBarLayout以及bottomBar。我确信这与之无关,因为当没有CoordinatorLayout行为时,正如我上面解释的那样,它再次显示出滞后。
这是我的recyclerView项目布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="vertical">
<include layout="@layout/contact_separator" />
<include layout="@layout/contact_detail" />
<LinearLayout
android:id="@+id/subItem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" />
</LinearLayout>
contact_separator和contact_detail都是ConstaintLayouts。
这是我设置recyclerView的方法:
mAdapter = new ContactsAdapter();
binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setAdapter(mAdapter);
final Observer<Resource<List<Contact>>> contactsObserver = resource -> {
if (resource instanceof Resource.Success) {
mContacts = ((Resource.Success<List<Contact>>) resource).getData();
mAdapter.setItems(mContacts, true);
}
};
这可能是什么原因?
没有运行项目就很难说,但是快速浏览(只需2-3分钟浏览您的适配器代码),就会发现一些“气味”。
您使用的是普通的RecyclerView.Adapter,应该/应该ListAdapter<T, K>
与aDiffUtilCallback
一起使用以避免notifyDataSetChanged()
在执行操作时使用setList(...)
(相反,您只需要执行操作,submitList(...)
然后让Adapter为您解决问题即可。
您的bind(...)
方法相当复杂且漫长;有两个潜在的循环和视图参数更改(窗口小部件尺寸),这至少会导致一次度量传递(随后是布局传递),所有这些都会在您提交列表时发生在视图持有者中的每个项目上。创建应用程序(销毁应用程序后)时,必须再次计算所有这些内容,因此回收站视图的setFixedSize = true(为什么需要此功能,鉴于您的适配器,这不是真实的)。如果固定大小为true,那么将避免调用requestLayout(),但这意味着您要告诉适配器其大小是恒定的(这意味着适配器可以根据项数进行增长/收缩,但所有项的大小均相同)。这是一种优化,但可能会咬人,这很可能不是您想要的。
您flagItems
是LinearLayout,您可以在运行时在bind方法内动态添加/删除视图到此线性布局。
您对subItem
(另一个LinearLayout)执行相同的操作。
此外,还有再次另一个回路(联系电话)在布局时可能再次修改的可能(约束集更改)。
所有这些(还有一些其他详细信息),但是现在就可以做...当涉及适配器时,它们是“红色标志”。
有趣的是,所有这一切都应该在更少的时间内发生,这需要Android渲染一帧(60毫秒?)。因此,您要求代码做很多工作并引发很多副作用,并期望它在60ms或更短的时间内完成。对于要绑定的每个EACH视图(取决于设备的屏幕尺寸),因此可以想象屏幕上可以容纳5个项目;RecyclerView会预先绑定一些内容,以便在滚动时做好准备。
我将从退后一步开始List<Contact> contacts
。可以更好地转换这些联系人以在RecyclerView上显示。关于显示什么/如何显示它的所有逻辑,应提前解决,并以最扁平/最简单的形式呈现给适配器(已经有其他工作要做)。type
通过将数据分解为不同的类型,并使适配器简单地为每种视图类型绑定正确的viewHolder,可以利用ViewHolders的优势。
因此,List<Contact>
您可以提供一个List<SomeOtherObject>
更不适合viewHolder的,而只包含您以后需要重新获取原始数据Contact
(或重建它)所需的数据,而不是一个。
然后,您可以从viewHolder#bind方法中简化并删除所有逻辑/决策,因为在确定要绑定的数据类型时,很多问题都可以解决。
我将从这里开始,因为您可以尝试优化所需的一切,但是您仍在要求适配器为您完成所有这些工作。
那是因为(我估计)事物已被缓存并预先计算(它们已经花了第一时间),所以因为您拥有FixedSize = true,所以RecyclerView知道(已被告知)每个ViewHolder的大小都不会改变,因此无需重新计算。
简而言之,您并没有使适配器具有更高的性能,只是告诉他花那么多时间一次。;)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句