Getx: Navigating to same route with offAllNamed causes UI updates to fail

Created on 10 Oct 2020  路  8Comments  路  Source: jonataslaw/getx

Navigating to the same route with Get.offAllNamed(HomeView.HOME) causes UI updates to fail and textControllers.text to be empty.

example:

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(
    GetMaterialApp(
        title: "Application",
        initialRoute: HomeView.HOME,
        getPages: [
          GetPage(
            name: HomeView.HOME,
            page: () => HomeView(),
            binding: HomeBinding(),
          ),
        ]),
  );
}

class HomeBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut<HomeController>(
      () => HomeController(),
    );
  }
}

class HomeController extends GetxController {
  final toggle = false.obs;
}

class HomeView extends GetView<HomeController> {
  static const HOME = '/home';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HomeView'),
        centerTitle: true,
      ),
      body: Center(
        child: Column(children: [
          Obx(
            () => ToggleButtons(
              children: <Widget>[
                Container(
                  child: Text(
                    'HELLO',
                  ),
                ),
                Container(
                  child: Text(
                    'BYE',
                  ),
                ),
              ],
              onPressed: (int index) {
                print("Toggle pressed $index");
                if (index == 0) {
                  controller.toggle.value = false;
                } else {
                  controller.toggle.value = true;
                }
              },
              isSelected: [!controller.toggle.value, controller.toggle.value],
            ),
          ),
          FlatButton(
            child: Text(
              'TO HOME',
              style: TextStyle(fontSize: 20),
            ),
            onPressed: () {
              Get.offAllNamed(HomeView.HOME);
            },
          ),
        ]),
      ),
    );
  }
}

Steps to reproduce the behavior

  1. Once the app is ran, Toggling between Hello and Bye works fine
  2. Click on "TO HOME" button
  3. Future toggles do not update UI

Expected behavior
Navigating to same route with offAllNamed should not destroy and re-create Controller.

Flutter Version:
1.22.0

Getx Version:
3.13.2

Describe on which device you found the bug:
Emulator Pixel_3a_API_30 & Xiaomi K20 Pro

bug

Most helpful comment

I'm thinking of creating an Id for the routes based on their first hashcode (Since Routes are builders, they lose the hashcode with the update of a superior widget, changing the theme, for example would affect this behavior if I based on the provided hashcode by dart, so I won't do that).
So I will store the first hashcode locally in the constructor, and use it as a fingerprint for the creation and removal of dependencies linked to the routes, so the creation and removal of dependencies will not be hostage to the route name, which can present problems like this .
I think this was a good issue, it gave me clarity on how to improve the system of self injection and dispose of dependencies.

All 8 comments

Instead of using Get.offAll, You can try this Get.until((route) => Get.currentRoute == HomeView.HOME);

Instead of using Get.offAll, You can try this Get.until((route) => Get.currentRoute == HomeView.HOME);

that does'nt make sense. He want to pop the current route and replace with an equal one, use get.until. get.offnamed or get.offallnamed won't make any difference

Unfortunaly I tested and indeed it stops working.

What happens:

  • when is opened, it works normally,
  • when you open another route erasing the current, it will dispose the controller, but it won't start the controller again
  • if you press some button in screen, only then the controller is initialized again, but it doesn't work

Instead of using Get.offAll, You can try this Get.until((route) => Get.currentRoute == HomeView.HOME);

that does'nt make sense. He want to pop the current route and replace with an equal one, use get.until. get.offnamed or get.offallnamed won't make any difference

Unfortunaly I tested and indeed it stops working.

What happens:

  • when is opened, it works normally,
  • when you open another route erasing the current, it will dispose the controller, but it won't start the controller again
  • if you press some button in screen, only then the controller is initialized again, but it doesn't work

That's true, I wanted to help with a quick fix: Which is, not closing the HomeController in the first place.

After running the code now, I can confirm the issue too.

  • It seems the new view is being rendered before the old Controller is closed.

Instead of using Get.offAll, You can try this Get.until((route) => Get.currentRoute == HomeView.HOME);

that does'nt make sense. He want to pop the current route and replace with an equal one, use get.until. get.offnamed or get.offallnamed won't make any difference
Unfortunaly I tested and indeed it stops working.
What happens:

  • when is opened, it works normally,
  • when you open another route erasing the current, it will dispose the controller, but it won't start the controller again
  • if you press some button in screen, only then the controller is initialized again, but it doesn't work

That's true, I wanted to help with a quick fix: Which is, not closing the HomeController in the first place.

After running the code now, I can confirm the issue too.

  • It seems the new view is being rendered before the old Controller is closed.

You're right.
In Flutter the layout of a page happens after the build of the second page.
And in this case, navigating to the same route will make the dispose happen and a new instance will not be created, because the dispose occured after build

I'm thinking of creating an Id for the routes based on their first hashcode (Since Routes are builders, they lose the hashcode with the update of a superior widget, changing the theme, for example would affect this behavior if I based on the provided hashcode by dart, so I won't do that).
So I will store the first hashcode locally in the constructor, and use it as a fingerprint for the creation and removal of dependencies linked to the routes, so the creation and removal of dependencies will not be hostage to the route name, which can present problems like this .
I think this was a good issue, it gave me clarity on how to improve the system of self injection and dispose of dependencies.

Thanks for looking into this.

For now I'm making a check within my navigation logic to make sure this doesn't happen.
if (Get.currentRoute != Routes.HOME) Get.offAllNamed(Routes.HOME);

One quick fix could be to skip navigation to the route internally if the current route is the same.

Hi. Just to add to this, because I've done exactly that in my app: don't navigate if you're on the current page.
And it works. But it still fails if the user navigates to a page, from the top level page (in which case the current route is no longer home) and instead of pressing back on the second page, they click a link in the navigation bar to go to the Home page.
In that case we still get the original issue.

Long story short, we still need a change within "GetX" along the lines of what @jonataslaw has described.

Thanks again for all your hard work.
You're doing an amazing job with this library.

I can't reproduce on last version, so I'm closing this issue.
If you can reproduce, please reopen the issue or open a new one. Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

manojeeva picture manojeeva  路  3Comments

aztecrabbit picture aztecrabbit  路  3Comments

wailashraf71 picture wailashraf71  路  4Comments

rupamking1 picture rupamking1  路  3Comments

jemariads picture jemariads  路  4Comments