Skip to content

[Android] Adding/removing external keyboard resets the focused text field #167858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
loic-sharma opened this issue Apr 25, 2025 · 2 comments
Closed
Assignees
Labels
a: text input Entering text in a text field or keyboard related problems P1 High-priority issues at the top of the work list platform-android Android applications specifically team-android Owned by Android platform team triaged-android Triaged by Android platform team

Comments

@loic-sharma
Copy link
Member

loic-sharma commented Apr 25, 2025

Steps to reproduce

  1. Create an app with a text field
  2. Run it on an Android device with no external keyboard connected
  3. Type something in the text field using the virtual keyboard
  4. Connect an external keyboard to the Android device

Expected results

I can continue typing in the text field using my external keyboard.

Actual results

The focused text field's content is reset.

Code sample

Code sample
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: Center(
          child: TextField(),
        ),
      ),
    ),
  );
}

Screenshots or Video

N/A

Logs

N/A

Flutter Doctor output

Doctor output
$ flutter doctor -v
[✓] Flutter (Channel master, 3.32.0-1.0.pre.256, on macOS 15.4.1 24E263 darwin-arm64, locale en) [1,831ms]
    • Flutter version 3.32.0-1.0.pre.256 on channel master at /Users/loicsharma/Code/flutter
    • Upstream repository git@github.com:flutter/flutter.git
    • Framework revision a1d15edcf6 (4 hours ago), 2025-04-25 11:25:16 -0700
    • Engine revision a1d15edcf6
    • Dart version 3.9.0 (build 3.9.0-55.0.dev)
    • DevTools version 2.45.0

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [2.3s]
    • Android SDK at /Users/loicsharma/Library/Android/sdk
    • Emulator version 34.1.20.0 (build_id 11610631) (CL:N/A)
    • Platform android-35, build-tools 34.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
      This is the JDK bundled with the latest Android Studio installation on this machine.
      To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment (build 17.0.9+0-17.0.9b1087.7-11185874)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 16.1) [1,351ms]
    • Xcode at /Applications/Xcode_16_1.app/Contents/Developer
    • Build 16B40
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [11ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2023.2) [11ms]
    • 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 17.0.9+0-17.0.9b1087.7-11185874)

[✓] VS Code (version 1.99.3) [10ms]
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.108.0

[✓] Connected device (2 available) [6.7s]
    • macOS (desktop) • macos  • darwin-arm64   • macOS 15.4.1 24E263 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 136.0.7103.48

[✓] Network resources [562ms]
    • All expected network resources are available.

• No issues found!
@loic-sharma loic-sharma added a: text input Entering text in a text field or keyboard related problems platform-android Android applications specifically team-android Owned by Android platform team labels Apr 25, 2025
@ash2moon ash2moon self-assigned this Apr 29, 2025
@ash2moon ash2moon added P1 High-priority issues at the top of the work list triaged-android Triaged by Android platform team labels Apr 29, 2025
@mboetger
Copy link
Contributor

mboetger commented May 1, 2025

#168100 Looks similar

@Renzo-Olivares
Copy link
Contributor

Renzo-Olivares commented May 21, 2025

Thanks to the investigation by @ash2moon it looks like this is the expected behavior on Android when configuration changes such as when external peripherals are connected/disconnected. See more information about configuration changes and how to handle them on Android here.

On Android connecting/disconnecting external peripherals causes a configuration change which causes the system to recreate the activity, in this scenario all state is lost. I confirmed this with a basic jetpack compose app with a TextField and RadioButtons and also observed that the state is lost when connecting/disconnecting peripherals. Jetpack compose has a solution for restoring state across configuration changes called rememberSaveable. I tried this out with a jetpack compose TextField and it works as expected.

On Flutter we have similar solutions to restore state across configuration changes and activity destruction, you can read more about them in Restore State on Android and RestorationManager which is the core class that handles state restoration. For the scenario in the issue there are two ways to enable state restoration for a TextField.

  1. Set restorationScopeId on MaterialApp, and provide a restorationId to a TextField that does not explicitly provide a controller.
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      restorationScopeId: 'materialRoot',
      home: Scaffold(
        body: Center(child: TextField(restorationId: 'myTextField')),
      ),
    ),
  );
}
  1. Set restorationScopeId on MaterialApp, mixin RestorationMixin into your State class and implement restorationId and restoreState, and provide a RestorableTextEditingController to TextField.
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(restorationScopeId: 'materialRoot', home: MyHomePage());
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with RestorationMixin {
  final RestorableTextEditingController _controller =
      RestorableTextEditingController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: TextField(controller: _controller.value)),
    );
  }

  @override
  String? get restorationId => 'myHomePage';

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    registerForRestoration(_controller, 'myTextEditingController');
  }
}

Besides RestorableTextEditingController there are also other Restorable primitives that can be used to restore state across configuration changes like RestorableBool, RestorableInt, RestorableString, and others a full list can be seen here.

Closing this issue as WAI for now because the Flutter behavior matches the Android behavior in the same scenario, and we have similar mechanisms to restore state. Feel free to reopen if this needs further discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: text input Entering text in a text field or keyboard related problems P1 High-priority issues at the top of the work list platform-android Android applications specifically team-android Owned by Android platform team triaged-android Triaged by Android platform team
Projects
None yet
Development

No branches or pull requests

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy