Skip to content

Application state is reset when connecting or disconnecting external peripherals #168100

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
Renzo-Olivares opened this issue Apr 30, 2025 · 4 comments
Assignees
Labels
a: mouse Issues related to using a mouse or mouse support a: text input Entering text in a text field or keyboard related problems P1 High-priority issues at the top of the work list team-android Owned by Android platform team triaged-android Triaged by Android platform team workaround available There is a workaround available to overcome the issue

Comments

@Renzo-Olivares
Copy link
Contributor

Renzo-Olivares commented Apr 30, 2025

Steps to reproduce

  1. Change application state by selecting different radio buttons, typing in text field, or enabling checkbox.
  2. Connect or disconnect external peripheral such as a mouse or keyboard.

Expected results

Applications state is not affected by connecting/disconnecting external peripherals.

Actual results

Applications state is reset when connecting/disconnecting external peripherals.

Code sample

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _textController = TextEditingController();
  int? _radioValue = 1;
  bool _isChecked = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ListView(
          children: <Widget>[
            const SizedBox(height: 8),
            TextField(
              controller: _textController,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Enter text',
                hintText: 'Type something here',
                prefixIcon: Icon(Icons.edit),
              ),
            ),
            const SizedBox(height: 20),
            Column(
              children: <Widget>[
                RadioListTile<int>(
                  title: const Text('Radio Option 1'),
                  value: 1,
                  groupValue: _radioValue,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue = value;
                    });
                  },
                ),
                RadioListTile<int>(
                  title: const Text('Radio Option 2'),
                  value: 2,
                  groupValue: _radioValue,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue = value;
                    });
                  },
                ),
                 RadioListTile<int>(
                  title: const Text('Radio Option 3'),
                  value: 3,
                  groupValue: _radioValue,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue = value;
                    });
                  },
                ),
              ],
            ),
            const SizedBox(height: 20),
            CheckboxListTile(
              title: const Text('Enable Checkbox'),
              value: _isChecked,
              onChanged: (bool? value) {
                setState(() {
                  _isChecked = value ?? false;
                });
              },
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

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

Screenshots or Video

Screenshots / Video demonstration
Screen_Recording_20250430_134352.mp4

Reproduced On

  • Samsung Galaxy S10 Tablet
@Renzo-Olivares Renzo-Olivares changed the title App state is reset when connecting or disconnecting external peripherals Application state is reset when connecting or disconnecting external peripherals Apr 30, 2025
@Renzo-Olivares Renzo-Olivares added the team-framework Owned by Framework team label Apr 30, 2025
@Piinks Piinks added team-android Owned by Android platform team and removed team-framework Owned by Framework team labels May 1, 2025
@Piinks
Copy link
Contributor

Piinks commented May 1, 2025

Touched base with jmagman (no ping), since this was identified as specific to the embedder, applied team-android.

@Piinks Piinks added a: text input Entering text in a text field or keyboard related problems a: mouse Issues related to using a mouse or mouse support labels May 1, 2025
@jesswrd
Copy link
Contributor

jesswrd commented May 6, 2025

from android triage: #167858 This is possibly a duplicate or a superset because it involves mice. @ash2moon will be looking into this.

@jesswrd jesswrd assigned jesswrd and ash2moon and unassigned jesswrd May 6, 2025
@jesswrd jesswrd added triaged-android Triaged by Android platform team P1 High-priority issues at the top of the work list labels May 6, 2025
@ash2moon
Copy link
Contributor

Looks like this issue stems from configuration changes causing an application recreation. Did some digging and found out that we need to add navigation to the configChanges in the AndroidManifest to prevent this behavior.

If this is a P0 for you team, I would recommend adding navigation to your AndroidManifest file. In the mean time I will work on adding this value to the default values when generating the manifest file.

@Piinks Piinks added the workaround available There is a workaround available to overcome the issue label May 14, 2025
@Renzo-Olivares
Copy link
Contributor Author

Closing this issue as WAI thanks to @ash2moon's investigation. You can read more about the motivation to close this issue here. Feel free to reopen if further discussion is needed.

Below is the original sample code updated with state restoration.

Enabling state restoration in the original sample code involves:

  1. Providing a restorationScopeId to MaterialApp.
  2. Mixing in RestorationMixin with the State class containing the state you want to restore, including implementing restorationId and restoreState.
  3. Making the state of TextField, RadioListTile, and CheckBoxListTile restorable by using restorable primitives like RestorableTextEditingController, RestorableIntN, and RestorableBool.
  4. Register any restorable values you want to restore in restoreState.
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(),
      debugShowCheckedModeBanner: false,
      restorationScopeId: 'materialRoot',
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> with RestorationMixin {
  final RestorableTextEditingController _textController =
      RestorableTextEditingController();
  final RestorableIntN _radioValue = RestorableIntN(1);
  final RestorableBool _isChecked = RestorableBool(false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ListView(
          children: <Widget>[
            const SizedBox(height: 8),
            TextField(
              controller: _textController.value,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Enter text',
                hintText: 'Type something here',
                prefixIcon: Icon(Icons.edit),
              ),
            ),
            const SizedBox(height: 20),
            Column(
              children: <Widget>[
                RadioListTile<int>(
                  title: const Text('Radio Option 1'),
                  value: 1,
                  groupValue: _radioValue.value,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue.value = value;
                    });
                  },
                ),
                RadioListTile<int>(
                  title: const Text('Radio Option 2'),
                  value: 2,
                  groupValue: _radioValue.value,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue.value = value;
                    });
                  },
                ),
                RadioListTile<int>(
                  title: const Text('Radio Option 3'),
                  value: 3,
                  groupValue: _radioValue.value,
                  onChanged: (int? value) {
                    setState(() {
                      _radioValue.value = value;
                    });
                  },
                ),
              ],
            ),
            const SizedBox(height: 20),
            CheckboxListTile(
              title: const Text('Enable Checkbox'),
              value: _isChecked.value,
              onChanged: (bool? value) {
                setState(() {
                  _isChecked.value = value ?? false;
                });
              },
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

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

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

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    registerForRestoration(_textController, 'textController');
    registerForRestoration(_radioValue, 'radioValue');
    registerForRestoration(_isChecked, 'isChecked');
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: mouse Issues related to using a mouse or mouse support a: text input Entering text in a text field or keyboard related problems P1 High-priority issues at the top of the work list team-android Owned by Android platform team triaged-android Triaged by Android platform team workaround available There is a workaround available to overcome the issue
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