Profiling Flutter Applications Using Performance DevTools
Learn how to profile an inefficient application by using Flutter DevTools

Search for a command to run...
Learn how to profile an inefficient application by using Flutter DevTools

https://idm.in/KhJrpHi XAUBOT is a Gold Forex Trading Robot developed by Adak Academy. With a high-profit margin and low drawdown, XAUBOT is the perfect addition to any trading platforms. telegram channel:https://t.me/xaubotAdvice
OpenClaw is a powerful, self-hosted AI assistant that connects to your tools to perform actions. Explore its Gateway architecture, real-world use cases, and security precautions.

Discover how neo-brutalism is shaping 2026 design trends. See how anti-design principles can create distinct, usable, and memorable product experiences.

When code breaks a pipeline, developers have to stop working and figure out why. This blog shows how an AI agent reads the error, finds the fix, and submits it for review all on its own.

GeekyAnts built a 5-agent fraud detection pipeline that makes decisions in under 200ms — 15x cheaper than single-model systems, with full explainability built in.

A deep dive into how GeekyAnts built a real-time AI fraud detection system that evaluates transactions in milliseconds using a hybrid multi-agent approach.

GeekyAnts Tech Blog
348 posts
GeekyAnts is an AI-powered digital product engineering and consulting company helping startups, enterprises, and Fortune 500 brands build scalable, future-ready digital solutions. Since 2006, we have delivered 800+ successful projects for 550+ global clients across healthcare, BFSI, retail, logistics, education, and enterprise technology. We help businesses accelerate digital transformation through strategy, design, engineering, and AI-led innovation.
In the previous article, we got an overview of the UI performance tools that can be used on Flutter. As we proceed with this article, let's take this learning further and start with the UI profiling of an inefficient Flutter app. Displaying long lists, handling complex animations or transitions has always been a daunting task for every Flutter developer due to the jank received during this process. In this article, we will be profiling an app that is used to render huge lists having transitions by making use of UI performance tools to identify issues and refactor the code. Towards the end, we will be able to measure how the app's performance has improved after refactoring the code.
Simulators or emulators have differences in hardware when compared to real devices. Additional checks like assertions are added to aid development when using the debug mode and the code is compiled JIT(just in time); whereas in profile or release mode, code is precompiled to transmit native instructions i.e AOT(ahead of time) which makes it more preferable for this process.
flutter run --profile






ListView for your application:import 'package:flutter/material.dart';
import 'package:ui_profiling/utils/utils.dart';
class LongListView extends StatefulWidget {
LongListView({
Key key,
}) : super(key: key);
@override
_LongListViewState createState() => _LongListViewState();
}
class _LongListViewState extends State<LongListView>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _offsetAnimation;
@override
void initState() {
super.initState();
_controller = initialiseController(const Duration(milliseconds: 700), this);
_offsetAnimation = setAnimation(_controller);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Lengthy List View"),
),
body: ListView(
children: [
for (var i = 0; i < 10000; i++) _buildLongList(i, _offsetAnimation)
],
),
);
}
Widget _buildLongList(var index, Animation animation) {
return SlideTransition(
position: animation,
child: Card(
elevation: 11,
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Container(
margin: EdgeInsets.only(
right: 20,
),
width: 100,
height: 100,
child: CircleAvatar(
backgroundImage:
AssetImage("assets/images/${getImage(index)}"),
)),
),
Padding(
padding: EdgeInsets.only(top: 15, bottom: 15),
child: Text(
'${getUserName(index)}',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
],
),
),
),
);
}

_buildLongList is the element that is poorly performing and we can get around to addressing this error.
Slide transition, ClipRRect, and Image widget. ListView is a large individual widget with ten thousand items but it isn't possible to display more than five at the same time.
Each list item has nearly nine widgets(SlideTransition, Card, Padding, ClipRRect, AssetImage, etc.) which makes building every single item on the list difficult.
ClipRRect tends to be an expensive widget when there are animations involved.
Images used in the example have dimensions(3744 × 5616) that are not compatible with the required size of the Image container(100 x 100). The images have to be decompressed from 3744 x 5616 to 100 x 100 which makes the entire process tedious.
We can load the visible list view items with the help of the ListView.builder which only renders the items visible on the screen
Each list item can be replaced with a stateful/stateless widget, which can be split into multiple widgets, instead of having each item return so many widgets.
We can also try adding a border-radius to the container or overlay the opaque corners onto a square instead of clipping it to a rounded rectangle.
ListView is here replaced by ListView.builder resulting in the following code:import 'package:flutter/material.dart';
import 'package:ui_profiling/utils/utils.dart';
class LongListBuilder extends StatefulWidget {
LongListBuilder({
Key key,
}) : super(key: key);
@override
_LongListBuilderState createState() => _LongListBuilderState();
}
class _LongListBuilderState extends State<LongListBuilder>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _offsetAnimation;
@override
void initState() {
super.initState();
_controller = initialiseController(const Duration(milliseconds: 700), this);
_offsetAnimation = setAnimation(_controller);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Lengthy List Builder"),
),
body: ListView.builder(
itemCount: 10000,
itemBuilder: (context, index) {
return ListItem(index, _offsetAnimation);
},
));
}
}
ListItem widget returns a ListCard widget along with the required transitions for the first ten items on the list as shown below:class ListItem extends StatelessWidget {
final int index;
final Animation animation;
ListItem(this.index, this.animation);
@override
Widget build(BuildContext context) {
if (index < 10)
return SlideTransition(
position: animation,
child: ListCard(index: index),
);
return ListCard(index: index);
}
}
ListCard widget in images are separated out into a ImageContainer widget as is shown below:class ListCard extends StatelessWidget {
const ListCard({
Key key,
@required this.index,
}) : super(key: key);
final int index;
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.none,
elevation: 11,
margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ImageContainer(index: index),
Padding(
padding: EdgeInsets.only(top: 15, bottom: 15),
child: Text(
'${getUserName(index)}',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
],
),
),
);
}
}
CircleAvatar, we can also take advantage of the BoxDecoration and display the image in the container itself. Use the code given below to implement this:class ImageContainer extends StatelessWidget {
const ImageContainer({
Key key,
@required this.index,
}) : super(key: key);
final int index;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: AssetImage(
"assets/images/400x300_${getImage(index)}",
),
),
borderRadius: BorderRadius.circular(200)),
margin: EdgeInsets.only(
right: 20,
),
width: 100,
height: 100,
);
}
}

Note: Certain expensive widgets like
Opacity,Chip,ShaderMask,ColorFilterandTextwithoverflowShader need to be used with careful consideration as they might triggersaveLayer()` behind the scenes.
In the example that we discussed, the application was designed to be inefficient because of which the profiling was not time-consuming. But if you are trying to profile a production-ready app, you will find that it is arduous to identify the root cause and this often involves dealing between the tradeoffs. The complete code of the app is available at GitHub.
After profiling the user interface of the app, we have learned how we can load huge lists and reduce the unnecessary rebuilding of widgets by splitting a large widget into multiple small widgets along with exploring how images of appropriate size can be maintained to reduce decompression. You can view the widget rebuilt counts for the current screen and frame in the Flutter plugin for Android Studio and IntelliJ.
The article comes to an end here. Hope you enjoyed profiling the Flutter application!