- Install
- Set up an editor
- Test drive
- Write your first Flutter app, part 1
- Learn more
- Flutter for Android developers
- Flutter for iOS developers
- Flutter for React Native developers
- Flutter for web developers
- Flutter for Xamarin.Forms developers
- Introduction to declarative UI
- Cookbook
- Codelabs
- Tutorials
- User interface
- Introduction to widgets
- Layouts in Flutter
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Introduction to animations
- Animations overview
- Animations tutorial
- Hero Animations
- Staggered Animations
- Advanced UI
- Slivers
- Taps, drags, and other gestures
- Widget catalog
- Data & backend
- State management
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Firebase
- Accessibility & internationalization
- Accessibility
- Internationalizing Flutter apps
- Platform integration
- Writing custom platform-specific code
- Packages & plugins
- Using packages
- Developing packages & plugins
- Background processes
- Tools & techniques
- Android Studio / IntelliJ
- Visual Studio Code
- Upgrading Flutter
- Hot reload
- Code formatting
- Debugging Flutter apps
- Using OEM debuggers
- Flutter's build modes
- Testing Flutter apps
- Performance best practices
- Flutter performance profiling
- Creating flavors for Flutter
- Preparing an Android App for Release
- Preparing an iOS App for Release
- Continuous Delivery using fastlane with Flutter
- Bootstrap into Dart
- Inside Flutter
- Platform specific behaviors and adaptations
- Technical Overview
- Technical videos
- FAQ
- Flutter widget index
- Install
- Windows install
- MacOS install
- Linux install
- Set up an editor
- Write your first Flutter app, part 1
- Learn more
- Cupertino (iOS-style) widgets
- Layout widgets
- Animation and motion widgets
- Retrieve the value of a text field
- Basic widgets
- Material Components widgets
- Animate the properties of a Container
- Fade a Widget in and out
- Add a Drawer to a screen
- Displaying SnackBars
- Exporting fonts from a package
- Updating the UI based on orientation
- Using Themes to share colors and font styles
- Using custom fonts
- Working with Tabs
- Building a form with validation
- Create and style a text field
- Focus on a Text Field
- Handling changes to a text field
- Retrieve the value of a text field
- Adding Material Touch Ripples
- Handling Taps
- Implement Swipe to Dismiss
- Display images from the internet
- Fade in images with a placeholder
- Working with cached images
- Basic List
- Create a horizontal list
- Creating a Grid List
- Creating lists with different types of items
- Place a floating app bar above a list
- Working with long lists
- Report errors to a service
- Animating a Widget across screens
- Navigate to a new screen and back
- Navigate with named routes
- Pass arguments to a named route
- Return data from a screen
- Send data to a new screen
- Fetch data from the internet
- Making authenticated requests
- Parsing JSON in the background
- Working with WebSockets
- Persist data with SQLite
- Reading and Writing Files
- Storing key-value data on disk
- Play and pause a video
- Take a picture using the Camera
- An introduction to integration testing
- Performance profiling
- Scrolling
- An introduction to unit testing
- Mock dependencies using Mockito
- An introduction to widget testing
- Finding widgets
- Tapping, dragging and entering text
- Development
- Introduction to widgets
- Layout tutorial
- Dealing with box constraints
- Adding interactivity to your Flutter app
- Adding assets and images
- Navigation & routing
- Navigate to a new screen and back
- Send data to a new screen
- Return data from a screen
- Navigate with named routes
- Animating a Widget across screens
- AnimatedList
- Sample App Catalog
- Animations overview
- Animations tutorial
- Staggered Animations
- Slivers
- Taps, drags, and other gestures
- Accessibility widgets
- Assets, images, and icon widgets
- Async widgets
- Input widgets
- Interaction model widgets
- Painting and effect widgets
- Scrolling widgets
- Styling widgets
- Text widgets
- State management
- Start thinking declaratively
- Differentiate between ephemeral state and app state
- Simple app state management
- List of state management approaches
- JSON and serialization
- Accessibility
- Internationalizing Flutter apps
- Writing custom platform-specific code
- Using packages
- Fetch data from the internet
- Developing packages & plugins
- Background processes
- Android Studio / IntelliJ
- Set up an editor
- Flutter inspector
- Creating Useful Bug Reports
- Visual Studio Code
- Set up an editor
- Upgrading Flutter
- Hot reload
- Code formatting
Flutter performance profiling
It’s been said that “a fast app is great, but a smooth app is even better.” If your app isn’t rendering smoothly, how do you fix it? Where do you begin? This guide shows you where to start, steps to take, and tools that can help.
Diagnosing performance problems
To diagnose an app with performance problems, you’ll enable the performance overlay to look at the UI and GPU threads. Before you begin, you want to make sure that you’re running in profile mode, and that you’re not using an emulator. For best results, you might choose the slowest device that your users might use.
Connect to a physical device
Almost all performance debugging for Flutter applications should be conducted on a physical Android or iOS device, with your Flutter application running in profile mode. Using debug mode, or running apps on simulators or emulators, is generally not indicative of the final behavior of release mode builds. You should consider checking performance on the slowest device that your users might reasonably use.
Run in profile mode
Flutter’s profile mode compiles and launches your application almost identically to release mode, but with just enough additional functionality to allow debugging performance problems. For example, profile mode provides tracing information to profiling tools.
Launch the app in profile mode as follows:
- In Android Studio and IntelliJ, use the Run > Flutter Run main.dart in Profile Mode menu item.
In VS Code, open your
launch.json
file, and set theflutterMode
property toprofile
(when done profiling, change it back torelease
ordebug
):"configurations": [ { "name": "Flutter", "request": "launch", "type": "dart", "flutterMode": "profile" } ]
From the command line, use the
--profile
flag:$ flutter run --profile
For more information on how the different modes work, see Flutter’s build modes.
You’ll begin by enabling the performance overlay, as discussed in the next section.
The performance overlay
The performance overlay displays statistics in two graphs that show where time is being spent in your app. If the UI is janky (skipping frames), these graphs help you figure out why. The graphs display on top of your running app, but they aren’t drawn like a normal widget—the Flutter engine itself paints the overlay and only minimally impacts performance. Each graph represents the last 300 frames for that thread.
This section describes how to enable the PerformanceOverlay, and use it to diagnose the cause of jank in your application. The following screenshot shows the performance overlay running on the Flutter Gallery example:
Performance overlay showing the GPU thread (top), and UI thread (bottom). The vertical green bars represent the current frame.Flutter uses several threads to do its work. All your Dart code runs on the UI thread. Although you have no direct access to any other thread, your actions on the UI thread have performance consequences on other threads.
Platform thread
The platform’s main thread. Plugin code runs here. For more information, see the UIKit documentation for iOS, or the MainThread documentation for Android. This thread is not shown in the performance overlay.UI thread
The UI thread executes Dart code in the Dart VM. This thread includes code that you wrote, and code executed by Flutter’s framework on your app’s behalf. When your app creates and displays a scene, the UI thread creates a layer tree, a lightweight object containing device-agnostic painting commands, and sends the layer tree to the GPU thread to be rendered on the device. Don’t block this thread! Shown in the bottom row of the performance overlay.GPU thread
The GPU thread takes the layer tree and displays it by talking to the GPU (graphic processing unit). You cannot directly access the GPU thread or its data but, if this thread is slow, it’s a result of something you’ve done in the Dart code. Skia, the graphics library, runs on this thread, which is sometimes called the rasterizer thread. Shown in the top row of the performance overlay.I/O thread
Performs expensive tasks (mostly I/O) that would otherwise block either the UI or GPU threads. This thread is not shown in the performance overlay.
For more information on these threads, see Architecture notes.
Each frame should be created and displayed within 1/60th of a second (approximately 16ms). A frame exceeding this limit (in either graph) fails to display, resulting in jank, and a vertical red bar appears in one or both of the graphs. If a red bar appears in the UI graph, the Dart code is too expensive. If a red vertical bar appears in the GPU graph, the scene is too complicated to render quickly.
The vertical red bars indicate that the current frame is expensive to both render and paint.When both graphs have red, start by diagnosing the UI thread (Dart VM).
Displaying the performance overlay
You can toggle display of the performance overlay as follows:
- Using the Flutter Inspector
- From the command line
- Programmatically
From the Flutter inspector
The easiest way to enable the PerformanceOverlay widget is in the Flutter inspector, which is available through the Flutter plugin for your IDE. The Inspector view opens by default when running an application. If the inspector isn’t open, you can display it as follows.
In Android Studio and IntelliJ IDEA:
- Select View > Tool Windows > Flutter Inspector.
In the toolbar, select the icon that looks like a bookshelf ().
The Flutter Inspector is available in Android Studio and IntelliJ. Learn more about what the Inspector can do in the Widget inspector doc, as well as the Flutter Inspector talk presented at DartConf 2018.
In VS Code
- Select View > Command Palette… to bring up the command palette.
- In the text field, enter “performance” and select Toggle Performance Overlay from the list that pops up. If this command isn’t available, make sure that the app is running.
From the Command line
Toggle the performance overlay using the P key from the command line.
Programmatically
You can programmatically enable the PerformanceOverlay widget by setting the showPerformanceOverlay
property to true
on the MaterialApp or WidgetsApp constructor:
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( showPerformanceOverlay: true, title: 'My Awesome App', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'My Awesome App'), ); } }
You are probably familiar with the Flutter Gallery example app. To use the performance overlay with Flutter Gallery, use the copy in the examples directory that was installed with Flutter, and run the app in profile mode. The program is written so that the app menu allows you to dynamically toggle the overlay, as well as enable checks for calls to saveLayer
and the presence of cached images.
Identifying problems in the UI graph
If the performance overlay shows red in the UI graph, start by profiling the Dart VM, even if the GPU graph also shows red.
Performance profiling with Dart DevTools
Dart DevTools provides features like profiling, examining the heap, and displaying code coverage. DevTool’s timeline view allows you to investigate the UI performance of your application on a frame-by-frame basis.
Identifying problems in the GPU graph
Sometimes a scene results in a layer tree that is easy to construct, but expensive to render on the GPU thread. When this happens, the UI graph has no red, but the GPU graph shows red. In this case, you’ll need to figure out what your code is doing that is causing rendering code to be slow. Specific kinds of workloads are more difficult for the GPU. They may involve unnecessary calls to saveLayer
, intersecting opacities with multiple objects, and clips or shadows in specific situations.
If you suspect that the source of the slowness is during an animation, use the timeDilation property to greatly slow the animation down.
You can also slow the animation speed using the Flutter Inspector. In the inspector’s gear menu, select Enable Slow Animations. If you want more control of the animation speed, set the timeDilation property in your code.
Is the slowness on the first frame, or on the whole animation? If it’s the whole animation, is clipping causing the slow down? Maybe there’s an alternative way of drawing the scene that doesn’t use clipping. For example, overlay opaque corners onto a square instead of clipping to a rounded rectangle. If it’s a static scene that’s being faded, rotated, or otherwise manipluated, maybe a RepaintBoundary can help.
Checking for offscreen layers
The saveLayer
method is one of the most expensive methods in the Flutter framework. It’s useful when applying post-processing to the scene, but it can slow your app and should be avoided if you don’t need it. Even if you don’t call saveLayer
explicitly, implicit calls may happen on your behalf. You can check whether your scene is using saveLayer
with the PerformanceOverlayLayer.checkerboardOffscreenLayers switch.
Once the switch is enabled, run the app and look for any images that are outlined with a flickering box. The box flickers from frame to frame if a new frame is being rendered. For example, perhaps you have a group of objects with opacities that are rendered using saveLayer
. In this case, it’s probably more performant to apply an opacity to each individual widget, rather than a parent widget higher up in the widget tree. The same goes for other potentially expensive operations, such as clipping or shadows.
When you encounter calls to saveLayer
, ask yourself these questions:
- Does the app need this effect?
- Can any of these calls be eliminated?
- Can I apply the same effect to an individual element instead of a group?
Checking for non-cached images
Caching an image with RepaintBoundary is good, when it makes sense.
One of the most expensive operations, from a resource perspective, is rendering a texture using an image file. First, the compressed image is fetched from persistent storage. The image is decompressed into host memory (GPU memory), and transferred to device memory (RAM).
In other words, image I/O can be expensive. The cache provides snapshots of complex hierarchies so they are easier to render in subsequent frames. Because raster cache entries are expensive to construct and take up loads of GPU memory, cache images only where absolutely necessary.
You can see which images are being cached by enabling the PerformanceOverlayLayer.checkerboardRasterCacheImages switch.
Run the app and look for images rendered with a randomly colored checkerboard, indicating that the image is cached. As you interact with the scene, the checkerboarded images should remain constant—you don’t want to see flickering, which would indicate that the cached image is being re-cached.
In most cases, you want to see checkerboards on static images, but not on non-static images. If a static image isn’t cached, you can cache it by placing it into a RepaintBoundary widget. Though the engine may still ignore a repaint boundary if it thinks the image isn’t complex enough.
Viewing the widget rebuild profiler
The Flutter framework is designed to make it hard to create applications that are not 60fps and smooth. Often, if you have jank, it’s because there is a simple bug causing more of the UI to be rebuilt each frame than required. The Widget rebuild profiler helps you debug and fix performance problems due to these sorts of bugs.
You can view the widget rebuilt counts for the current screen and frame in the widget inspector. For details on how to do this, see Show performance data in the Android Studio / IntelliJ page.
Debug flags
Flutter provides a wide variety of debug flags and functions to help you debug your app at various points along the development cycle. To use these features, you must compile in debug mode. The following list, while not complete, highlights some of the more useful flags (and one function) from the rendering library for debugging performance issues.
You can set these flags either by editing the framework code, or by importing the module and setting the value in your main()
method, following by a hot restart.
debugDumpRenderTree()
Rather than using this flag to dump the render tree to a file, view the render tree in the widget inspector. To do so, bring up the widget inspector and select the Render Tree tab.debugPaintLayerBordersEnabled
debugRepaintRainbowEnabled
You can enable this flag in the widget inspector by bringing up the More Actions menu, and selecting Show Repaint Rainbow. If any static widgets are rotating through the colors of the rainbow (for example, a static header), those areas are candidates for adding repaint boundaries.debugPrintMarkNeedsLayoutStack
Enable this flag if you’re seeing more layouts than you expect (for example, on the timeline, on a profile, or from aprint
statement inside a layout method). Once enabled, the console is flooded with stack traces showing why each render object is being marked dirty for layout.debugPrintMarkNeedsPaintStacks
Similar todebugPrintMarkNeedsLayoutStack
, but for excess painting.
You can learn about other debug flags in Debugging Flutter apps.
Benchmarking
You can measure and track your app’s performance by writing benchmark tests. The Flutter Driver library provides support for benchmarking. Using this integration test framework, you can generate metrics to track the following:
- Jank
- Download size
- Battery efficiency
- Startup time
Tracking these benchmarks allows you to be informed when a regression is introduced that adversely affects performance.
For more information, see Integration testing, a section in Testing Flutter apps.
More information
The following resources provide more information on using Flutter’s tools and debugging in Flutter:
- Debugging Flutter apps
- Widget inspector
- Flutter Inspector talk, presented at DartConf 2018
- Why Flutter Uses Dart, an article on Hackernoon
- Dart DevTools: performance tooling for Dart and Flutter apps
- Flutter API docs, particularly the PerformanceOverlay class, and the dart:developer package
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论