Common Flutter Performance Pitfalls and Their Solutions at Soul App
This article details several real‑world Flutter performance problems encountered at Soul—including excessive memory usage for emojis, iOS 14 debug launch restrictions, high CPU consumption of Lottie animations, background‑foreground flickering, and PlatformView memory leaks—and provides concrete mitigation strategies with code examples.
Flutter has become a popular cross‑platform framework, but its adoption at Soul revealed a series of performance pitfalls that developers need to be aware of.
1. Emoji Rendering Consumes Over 120 MB
Displaying a single Apple Emoji on iOS caused memory usage to jump by more than 120 MB because Flutter does not reuse the native emoji buffer; it allocates a full Sbix table for each emoji.
// font_skia.cc
const size_t table_size = typeface->getTableSize(tag);
if (table_size == 0)
return nullptr;
void* buffer = malloc(table_size);
if (buffer == nullptr)
return nullptr;The team mitigated the issue by using an external Texture to render emojis on the native side, thus reusing the system buffer.
2. iOS 14 Debug Builds Require Xcode Connection
On iOS 14 devices, FlutterEngine fails to start a Debug build because the JIT‑based Dart VM is no longer supported, leading to silent launch failures.
The solution involves ensuring proper Xcode attachment and using the appropriate engine configuration.
3. Lottie Animations Use 30% More CPU Than Native
Flutter’s third‑party Lottie component does not reuse native rendering paths, resulting in noticeably higher CPU usage.
Switching to a native Lottie implementation via PlatformView and setting LottieRendeingEngineCoreAnimation on iOS aligns CPU consumption with native performance.
4. Android Background‑Foreground Switch Causes Screen Flicker
When the app returns from background, mismatched lifecycle events can leave frame scheduling in an incorrect state, producing visual flicker.
// main.dart
PageVisibilityBinding.instance.addGlobalObserver(AppLifecycleObserver());
SoulBinding();
WidgetsFlutterBinding.ensureInitialized();
class SoulBinding extends WidgetsFlutterBinding with BoostFlutterBinding {}Adjusting FlutterBoost’s lifecycle handling or overriding the default back‑foreground events resolves the issue.
// Disable default handling
FlutterBoostSetupOptions.Builder().shouldOverrideBackForegroundEvent(true).build();
// Manually send events
app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
// foreground
FlutterBoost.instance().plugin.onForeground()
// background
FlutterBoost.instance().plugin.onBackground()
});5. PlatformView Leads to Android Activity Memory Leak
Improper disposal of PlatformView objects leaves them retained by PlatformViewsController , causing leaks detected by LeakCanary.
private final MethodChannel.MethodCallHandler parsingHandler = new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
// handler may be null after detach, preventing dispose
if (handler == null) {
return;
}
switch (call.method) {
case "create":
create(call, result);
break;
case "dispose":
dispose(call, result);
break;
default:
result.notImplemented();
}
}
};A reflective disposal function that manually invokes the hidden dispose method on the PlatformViewsChannel resolves the leak.
fun dispose(engine: FlutterEngine, id: Int) {
try {
val controller = engine.platformViewsController
val field = controller.javaClass.getDeclaredField("channelHandler")
field.isAccessible = true
val obj = field[controller]
if (obj is PlatformViewsChannel.PlatformViewsHandler) {
val method = obj.javaClass.getDeclaredMethod("dispose", Int::class.java)
method.isAccessible = true
method.invoke(obj, id)
}
} catch (e: Exception) {
e.printStackTrace()
}
}6. Conclusion
Despite numerous pitfalls—from memory spikes to CPU overhead and lifecycle quirks—systematic debugging and targeted workarounds enable Flutter to remain a productive cross‑platform solution, and ongoing improvements from the Flutter team continue to reduce these issues.
Soul Technical Team
Technical practice sharing from Soul
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.