Multiple Rebuild issue on opening a keyboard
Hello, there's an issue with flutter 2.10.5 when opening keyboard and using responsive_builder. It will call build and didChangeDependencies multiple times. This is not happening in 2.8.1.
2.8 video below:
https://user-images.githubusercontent.com/19194749/171528794-777f5898-1077-4cad-9fce-fe83235788bc.mov
2.10.5 video below
https://user-images.githubusercontent.com/19194749/171528700-e5351981-514f-43a3-a7e8-e24b06257e6b.mov
You can use this sample demo: https://github.com/marctan/demo_rebuild
Hi @marctan, Thanks for filing the issue. Unfortunately, we do not provide support to older versions of flutter, I would suggest upgrading to the latest stable 3.0.1 where you won't see multiple rebuilds.
@maheshmnj
Hi @marctan, Thanks for filing the issue. Unfortunately, we do not provide support to older versions of flutter, I would suggest upgrading to the latest stable 3.0.1 where you won't see multiple rebuilds.
Thanks, but unfortunately, it also happens in version 3. Tried both in 3.0.0 and 3.0.1
https://user-images.githubusercontent.com/19194749/171603692-fc065517-a534-4eb5-a906-3e24404657d9.mov
Sorry I should have mentioned this is happening because of the third-party package responsive_builder I would suggest filing this issue in their dedicated repo. Also, Please see thee below code sample which works as expected on commenting the part of code which uses responsive_builder .
code sample
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Home(),
);
}
}
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: const Center(child: Text('hello')),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (_) {
return const TestScreen();
}));
},
child: const Icon(Icons.add),
),
);
}
}
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
@override
void didChangeDependencies() {
print('log test 1');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('log test 2');
return SafeArea(
child: Scaffold(
body: Container(
margin: EdgeInsets.symmetric(
horizontal: 22.0,
// horizontal: getValueForScreenType(
// context: context,
// mobile: 22,
// ),
),
child: const TextField(),
),
),
);
}
}
Closing as this is not an issue with flutter.
Hi @maheshmnj
I can reproduce that by minimize the code.
The root cause problem cause by MediaQuery.of(context)
When without MediaQuery.of(context):
https://user-images.githubusercontent.com/60456103/172323126-81dcc149-f8e5-4e21-8a2a-a764a801377f.mov
When with MediaQuery.of(context):
https://user-images.githubusercontent.com/60456103/172323293-81248af7-88ad-4141-9ebf-142900b5b705.mov
It happened on 2.10.5 and 3.0.1 also. Please help take look at the demo above.
code example:
import 'package:flutter/material.dart';
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
@override
void didChangeDependencies() {
print('didChangeDependencies');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context);
print('build');
return SafeArea(
child: Scaffold(
body: Container(
margin: EdgeInsets.symmetric(
horizontal: 2,
),
child: const TextField(),
),
),
);
}
}
@cuonghoang96 This is working as intended since opening keyboard will change the MediaQuery. From the MediaQuery docs
Querying the current media using [MediaQuery.of] will cause your widget to rebuild automatically whenever the [MediaQueryData] changes (e.g., if the user rotates their device).
You can make use of LayoutBuilder to prevent rebuilds on keyboard focus
code sample
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const TestScreen(),
);
}
}
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
@override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
@override
void didChangeDependencies() {
print('didChangeDependencies');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constrains) {
print('build');
return Scaffold(
body: Center(
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 2,
),
child: const TextField(),
),
),
);
});
}
}
is is working as intended since opening keyboard will change the MediaQuery. From the MediaQuery docs
is it normal? in flutter 2.8 the build is called only a few times as you can see from the video. but in flutter 3, the build is called a lot and multiple times.
@maheshmnj
When in flutter 2.8, it only call one time when open and hide keyboard. And that's oke. But in >2.10,
opening keyboard will change the MediaQuery
is call over 8 9 times, which will lead to the weird behaviour: If user fast type when open keyboard, it will close the keyboard immediately. User need to wait 1 or 2 seconds to use it normally. Can you help check that in real device?
Reopening based on the above comment
@cuonghoang96, Thanks for the info I did verify in flutter stable 2.8.0 on ios, and the build is called only once when the keyboard shows up while in the new stable release 3.0.1 it is called multiple times. However, on android the build is triggered multiple times in stable 2.8.0
logs (when keyboard is launched once)
logs (2.8.0)
Could not load custom device from config index 0: Expected enabled to be a boolean.
Launching lib/main.dart on iPhone 12 Pro in debug mode...
Xcode build done. 12.4s
Connecting to VM Service at ws://127.0.0.1:49228/nS58gdOdGlk=/ws
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
logs (3.0.1)
Restarted application in 357ms.
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter: didChangeDependencies
flutter: build
flutter doctor -v (2.8.0)
[✓] Flutter (Channel stable, 2.8.0, on macOS 12.4 21F79 darwin-arm, locale en-IN)
• Flutter version 2.8.0 at /Users/mahesh/Documents/flutter_dev
• Upstream repository unknown
• Framework revision cf44000065 (6 months ago), 2021-12-08 14:06:50 -0800
• Engine revision 40a99c5951
• Dart version 2.15.0
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
• Android SDK at /Users/mahesh/Library/Android/sdk
• Platform android-32, build-tools 33.0.0-rc4
• ANDROID_HOME = /Users/mahesh/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• CocoaPods version 1.11.2
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.2)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin version 61.2.4
• Dart plugin version 212.5080.8
[✓] VS Code (version 1.67.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.42.0
[✓] Connected device (4 available)
• Redmi K20 Pro (mobile) • 192.168.1.3:5555 • android-arm64 • Android 11 (API 30)
• iPhone 12 Pro (mobile) • 6AE1D692-DB57-4C3E-ADCA-66842182426B • ios •
com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 12.4 21F79 darwin-arm
• Chrome (web) • chrome • web-javascript • Google Chrome 102.0.5005.61
• No issues found!
flutter doctor -v (mac)
[✓] Flutter (Channel stable, 3.0.1, on macOS 12.3 21E230 darwin-arm, locale en-IN)
• Flutter version 3.0.1 at /Users/mahesh/Documents/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision fb57da5f94 (3 days ago), 2022-05-19 15:50:29 -0700
• Engine revision caaafc5604
• Dart version 2.17.1
• DevTools version 2.12.2
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
• Android SDK at /Users/mahesh/Library/Android/sdk
• Platform android-32, build-tools 31.0.0
• ANDROID_HOME = /Users/mahesh/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
• All Android licenses accepted.
[!] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
! CocoaPods 1.10.2 out of date (1.11.0 is recommended).
CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin
usage on the Dart side.
Without CocoaPods, plugins will not work on iOS or macOS.
For more info, see https://flutter.dev/platform-plugins
To upgrade see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin version 61.2.4
• Dart plugin version 212.5080.8
[✓] VS Code (version 1.66.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.40.0
[✓] Connected device (4 available)
• Redmi K20 Pro (mobile) • 192.168.1.2:5555 • android-arm64 • Android 11 (API 30)
• iPhone 12 Pro (mobile) • 19FD0231-BFF0-441D-B584-AD94C4084525 • ios •
com.apple.CoreSimulator.SimRuntime.iOS-15-2 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 12.3 21E230 darwin-arm
• Chrome (web) • chrome • web-javascript • Google Chrome 101.0.4951.64
[✓] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 1 category.
[✓] Flutter (Channel master, 3.1.0-0.0.pre.1138, on macOS 12.4 21F79 darwin-arm, locale en-IN)
• Flutter version 3.1.0-0.0.pre.1138 at /Users/mahesh/Documents/flutter_master
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision d9be807192 (26 hours ago), 2022-06-06 21:16:49 -0700
• Engine revision 48864fc837
• Dart version 2.18.0 (build 2.18.0-170.0.dev)
• DevTools version 2.14.0
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
• Android SDK at /Users/mahesh/Library/Android/sdk
• Platform android-32, build-tools 33.0.0-rc4
• ANDROID_HOME = /Users/mahesh/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• CocoaPods version 1.11.2
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)
[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
• IntelliJ at /Applications/IntelliJ IDEA CE.app
• Flutter plugin version 61.2.4
• Dart plugin version 212.5080.8
[✓] VS Code (version 1.67.2)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.42.0
[✓] Connected device (3 available)
• iPhone 12 Pro (mobile) • 6AE1D692-DB57-4C3E-ADCA-66842182426B • ios •
com.apple.CoreSimulator.SimRuntime.iOS-14-5 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 12.4 21F79 darwin-arm
• Chrome (web) • chrome • web-javascript • Google Chrome 102.0.5005.61
[✓] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!
Labeling this issue for further insights from the team.
Adding a regression label, since the widget does not rebuild multiple times in stable 2.8.
cc: @goderbauer
rebuild multiple times in stable 3.0.5
#97928 will fix this
I m facing same issue with android😐😐😐
I think the rebuild is expected. Because when keyboard changes, the MediaQuery change signal will be sent every frame when keyboard height changes. And because of this, we will have a keyboard animation in framework side (both iOS and android). So I think this is expected.
I think the rebuild is expected. Because when keyboard changes, the
MediaQuerychange signal will be sent every frame when keyboard height changes. And because of this, we will have a keyboard animation in framework side (both iOS and android). So I think this is expected.
I think this issue is still open because it was a regression from the previous flutter version. It wasn't rebuilding that much in last version. Im wondering it is because of the newly introduced IOS keyboard animation. If so I think then the MediaQuery change is justified.
However just because it is working as intended doesn't means its working at the most efficient level and as some people has mentioned the multiple rebuild can cause jank in more complicated apps. Im hoping to see https://github.com/flutter/flutter/pull/97928 land and improve the situation.
We confirm we experience janks caused by multiple rebuilds when opening keyboard on both ios and android. Janks might get unnoticed if testing with simple screens, but issue is severe with heavy screens.
I think should keep the rebuild inside the scaffold.... We should notice all places using MediaQuery.of(context)
Or use Builder widget to keep build area small as possible
class TextFieldPage extends StatefulWidget {
const TextFieldPage({Key? key}) : super(key: key);
@override
State<TextFieldPage> createState() => _TextFieldPageState();
}
class _TextFieldPageState extends State<TextFieldPage> {
@override
Widget build(BuildContext context) {
print("page build");
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
const Spacer(),
const Text('Keyboard animation', style: TextStyle(fontSize: 26)),
const Spacer(),
Builder(builder: (BuildContext builderCtx) {
print('builder build');
return SizedBox(
/// If you use context, the whole page will be rebuild, you will see log "page build" and "builder build",
/// but use builderCtx (after change you need to hot restart or recreate this page)
/// you will only see log "builder build"
height: 60 + MediaQuery.of(builderCtx).padding.bottom,
child: const CupertinoTextField(
decoration: BoxDecoration(color: Colors.red),
));
}),
],
),
);
}
}
@luckysmg Thanks will check this!
With me. I created a new MediaQuery widget to prevent rebuild when keyboard height change. It will listen on keyboard height change and put the height into an ChangeNotifier. Check here: https://github.com/phuongtinhbien/bloc_base_core/blob/master/lib/src/presentation/manager/theme/app_media_query.dart https://github.com/phuongtinhbien/bloc_base_core/blob/master/lib/src/presentation/widgets/keyboard_spacing.dart
@phuongtinhbien thanks! Will try this 👌
@delfme any thing work with you ?
@Joseph-Nathan nothing. Callum’s PR should be the solution to this https://github.com/flutter/flutter/pull/114459
its also happening in 3.7.12 tested on : IOS 16.3.1, IPhone x IOS 16.3.1, IPhone 13 mini
I face same issue, rebuild called 20+ time when keyboard show/hide
i agree with @luckysmg , doing investigations i notice rebuilds starts when using MediaQuery.of(context)
try to avoid use MediaQuery.of on the widget body , instead you can use Builder for the part you wanted to rerender, in case using builder the builder body be the only part thats rebuild whenever keyboard open\close.
also in case of using MediaQuery.of(context).size.width\height you can get the value once when the app open and save it in static variable or any state management way.
I have the same problem. I have removed MediaQuery.of in my entire project, but it still updates the screen 10 times when I open the keyboard.
I don't understand why it happens
removed MediaQuery.of in my entire project, but it still updates the screen 10 times when
Did you solve the problem? I have the same issue.
This issue happened on Android too. Tested on Flutter 3.10.5 stable.
The triaged-ios label is irrelevant if there is no team-ios label or fyi-ios label.
Is there any update about this problem, please?