I’m trying to debug a janky Flutter app using Flutter DevTools. I am new to DevTools and experiencing a confusion when dealing with the frame chart. While profiling the app, I can clearly see the jank in the UI, but not a single jank frame in the frame chart in DevTools.
I’ve created a sample Flutter app to demonstrate the problem. The app has a ListView and an artificially added jank that happens each time when a list item goes out of the screen due to scrolling. After launching the app in Profile mode, I slowly drag the list upwards and clearly observe janky UI just like I expect. However, I’m not able to see any kind of indication of jank in DevTools. In fact, the slowest frame that I could see in the chart was about 7 ms.
I have to mention that I’m able to get some red frames in the chart if I scroll abruptly enough, but that doesn’t give me a hint why there are no red frames when I’m dragging the list slowly.
Here’s the sample code:
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final ScrollController _scrollController;
int _currentFirstVisibleIndex = 0;
void _onScroll() {
double scrollOffset = _scrollController.offset;
const itemHeight = 66.0;
final newFirstIndex = scrollOffset < itemHeight
? 0
: (scrollOffset / itemHeight).ceil();
if (newFirstIndex == _currentFirstVisibleIndex) {
return;
}
_currentFirstVisibleIndex = newFirstIndex;
// Artificial jank:
_fibonacci(40);
}
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController.addListener(_onScroll);
}
@override
void dispose() {
super.dispose();
_scrollController.removeListener(_onScroll);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: ListView.separated(
controller: _scrollController,
itemBuilder: (_, index) => Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 12.0,
),
child: Text(
'Item $index',
style: const TextStyle(fontSize: 18),
),
),
itemCount: 100,
separatorBuilder: (_, __) => const Divider(
thickness: 0,
indent: 12,
color: Colors.black87,
),
),
);
}
}
int _fibonacci(int n) {
if (n == 0 || n == 1) {
return n;
}
return _fibonacci(n - 1) + _fibonacci(n - 2);
}
toughwombat is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.