fix: borrow list ANR from infinite-height grid measurement - #176
Open
A1nair wants to merge 11 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
起因
在一加Ace2上点击图书馆信息之后卡死闪退
使用
adb logcat获取原因Input dispatching timed out ... Waited 5000ms说明点击后主线程被阻塞超过 5 秒,不是普通 Dart 异常崩溃,而是主 isolate 陷入同步死循环 / 无限布局。DartWorker后台线程当时占用 ~6.2% CPU,但主 UI isolate 卡死。布局循环
LayoutBuilder 无限布局循环:外层
_RenderLayoutBuilder(来自BorrowListView的LayoutBuilder)与内层_LayoutBuilderElement(来自AlignedGridView内部的SliverLayoutBuilder)互相触发布局,Flutter 的布局深度保护触发 Layout cycle。去掉外层 LayoutBuilder 后变成 OOM
把
BorrowListView的LayoutBuilder临时去掉后,profile 日志由"布局循环"变为:这证明循环发生在测量/分配阶段(不是 build 阶段),且是无限分配——与"网格对每张卡片反复测量"的假设一致。
为什么卡片会被测成无限高
flutter_staggered_grid_view-0.7.0源码:SliverAlignedGrid.build(sliver_aligned_grid.dart:132)每行用
UniformTrack把一行里所有卡片拉伸到最宽那张的高度。RenderUniformTrack._computeSize(uniform_track.dart:155-180)关键点:
UniformTrack是SliverList的子项。在滚动 sliver 中,子 box 收到的主轴(纵向)约束maxHeight = double.infinity(sliver 主轴高度无界,子项高度由其自身内容决定)。于是:mainAxisExtent = constraints.maxHeight = double.infinitychildMainAxisExtent = ((infinity + spacing) / division) - spacing = double.infinityBorrowInfoCard被以BoxConstraints.tightFor(height: double.infinity)布局,即 minHeight = maxHeight = 无限。修复
lib/page/library/borrow_info_card.dart把卡片内容的最外层
Row用SizedBox(height: 140)包裹:AlignedGridView内部UniformTrack会以tightFor(height: infinity)测量每张卡;BorrowInfoCard顶层的.expanded()会把卡片撑成无限高,导致整张网格测量不收敛。用SizedBox(height: 140)给卡片一个有限且确定的高度,覆盖传入的无限高约束,使网格测量一次收敛。140 为 250 * 0.5 留有余量。
lib/page/library/borrow_list_view.dart去掉外层的
LayoutBuilder,改用一次性计算的MediaQuery求列数,并增加最小值约束: