Open darwin-morocho opened 4 years ago
Hi @the-meedu-app, I was unable to reproduce the problem with your code, as there are many parts missing, so I made a basic code and the controller is not being removed from memory when I do a hot reload. Could you test with this code below to see if it happens on your computer? Perhaps it is some widget (for example, InnerDrawer) that is causing this. Feel free to change the code and try to cause the problem.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(GetMaterialApp(
initialRoute: '/home',
getPages: [
GetPage(
name: '/home',
page: () => HomePage(),
),
GetPage(
name: '/login',
page: () => LoginPage(),
binding: LoginBinding(),
),
],
));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HOME')),
body: Center(
child: RaisedButton(
onPressed: () => Get.toNamed('/login'),
child: Text('Login'),
),
),
);
}
}
class LoginBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<LoginController>(() => LoginController());
}
}
class LoginController extends GetxController {
final message = 'Welcome'.obs;
}
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: Container(
child: GetBuilder<LoginController>(
autoRemove: false,
builder: (_) => Text('Message: ${_.message.value}')
),
),
);
}
}
Hi @the-meedu-app, I was unable to reproduce the problem with your code, as there are many parts missing, so I made a basic code and the controller is not being removed from memory when I do a hot reload. Could you test with this code below to see if it happens on your computer? Perhaps it is some widget (for example, InnerDrawer) that is causing this. Feel free to change the code and try to cause the problem.
import 'package:flutter/material.dart'; import 'package:get/get.dart'; void main() { runApp(GetMaterialApp( initialRoute: '/home', getPages: [ GetPage( name: '/home', page: () => HomePage(), ), GetPage( name: '/login', page: () => LoginPage(), binding: LoginBinding(), ), ], )); } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('HOME')), body: Center( child: RaisedButton( onPressed: () => Get.toNamed('/login'), child: Text('Login'), ), ), ); } } class LoginBinding extends Bindings { @override void dependencies() { Get.lazyPut<LoginController>(() => LoginController()); } } class LoginController extends GetxController { final message = 'Welcome'.obs; } class LoginPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Login')), body: Container( child: GetBuilder<LoginController>( autoRemove: false, builder: (_) => Text('Message: ${_.message.value}') ), ), ); } }
I'am using the package inner_drawer so I not sure if the problem is the InnerDrawer because it is a child of a GetBuilder. I will remove InnerDrawer to check if the problem persists
Ok, I await your feedback
Hi, Same for me, controller removed on hot reload . I am using drawer, and I think it happens in the navigation (Get.back(); ) after doing a hot reload. Regards
Ok, I await your feedback
Same problem removing InnerDrawer widget
Ok, I await your feedback
Same problem removing InnerDrawer widget
the problem occurs event if the screen is just using a controller with a simple from. I'm not sure if the problem only happens when I'am using bindings to inject my controller in the page
I am having the same issue .. I use hot restart to reload controllers.. as hot reload does not show any changes. Most likely it's deleting GetXController.. could it be because I'm using BottomNavigationBar and loading pages on body: on change of selected index?
@the-meedu-app, @pasblin or @prakash-indorkar, can you put more parts of your code so that we can reproduce the problem just by copying and pasting your code in my editor? You can omit the confidential parts by placing a container. I can debug with the GetX package source code
Hi Sorry I shared my code through live share link which might not be helpful.
Sharing link for repo in GitHub.. code is in .zip file. This is in very early stage.. I still learning, and from beginning it self I am using GetX. Please have a look.
https://github.com/prakash-indorkar/sharing.git
Thanks once again.
Sent from Mailhttps://go.microsoft.com/fwlink/?LinkId=550986 for Windows 10
From: Eduardo Florencemailto:notifications@github.com Sent: Wednesday, 4 November 2020 5:11 AM To: jonataslaw/getxmailto:getx@noreply.github.com Cc: prakash-indorkarmailto:prakash.indorkar@outlook.com; Mentionmailto:mention@noreply.github.com Subject: Re: [jonataslaw/getx] Visual Studio Code hot reload delete a GetxController from memory (#749)
@the-meedu-apphttps://github.com/the-meedu-app, @pasblinhttps://github.com/pasblin or @prakash-indorkarhttps://github.com/prakash-indorkar, can you put more parts of your code so that we can reproduce the problem just by copying and pasting your code in my editor? You can omit the confidential parts by placing a container. I can debug with the GetX package source code
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/jonataslaw/getx/issues/749#issuecomment-721431754, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AONSOGW6X3TO6OOGJCW3GDTSOCIIZANCNFSM4TCNB6YQ.
@prakash-indorkar, what are the steps to reproduce the problem after running the app?
As per your recommendation, I used lazyput with fenix.
class AuthBinding extends Bindings { @override void dependencies() { Get.lazyPut(() => AuthService(), fenix: true); Get.lazyPut(() => AuthController(), fenix: true); Get.lazyPut(() => UserController(), fenix: true); Get.lazyPut(() => HomeController(), fenix: true); Get.lazyPut(() => SharingService(), fenix: true); //Get.lazyPut(() => SharingController(), fenix: true); <=========== If I put this my sharing page do not show anything. Get.put(SharingController(), permanent: true); <==== If I use this .. SharingHomepage works fine. }
Not exactly the steps but .. as soon as I login and in the homepage .. first time it loads .. the if I move to other pages .. and come back on SharingHomePage.. contents not visible ( due to deletion of SharingControllers lazy instance.. ) If I use Get.put with permanent true. then it works fine.. Also I want to findout how to update the page based on streams of other collection data. For example in my case.. SharingHomePage is the main page and all the data is coming is from the Sharing collection.. a part of data is saved in Users collection which I am listing on users stream. So if any changes happen on Sharing Stream the page refresh and show new data. But when data related to Sharing in Users stream changes .. it does refresh the page. Please forward any example using firebase and getx pattern. if any ..
Thanks for your help, really appreciated. Regards, prakash
haha .. I figured it out..
I used different tags for each page binding using BindingsBuilder().
Here is my workaround .. It may be helpful if anyone using BottomNavigationBar with GetX.
Please have a look if anything can be improved in my code..
HomePage.dart
class HomePage extends GetWidget
* HomeController.dart ***
class HomeController extends GetxController {
static HomeController to = Get.find
final _currentIndex = 0.obs;
final List
int get currentIndex => _currentIndex.value;
set currentIndex(value) { if (_currentIndex.value != value) { _currentIndex.value = value; } } }
//...page_routes.dart.....................
GetPage(
name: '/home',
page: () => HomePage(),
binding: BindingsBuilder(() {
switch (HomeController.to.currentIndex) {
case 0:
Get.lazyPut(() => SharingController(), tag: 'mainhomepage');
break;
case 1:
Get.lazyPut(() => SharingController(), tag: 'mywatchlist');
break;
case 2:
Get.lazyPut(() => SharingController(), tag: 'mylistings');
break;
case 3:
Get.lazyPut(() => SharingController(), tag: 'addnew');
break;
case 4:
Get.lazyPut(() => SharingController(), tag: 'inboxpage');
break;
default:
Get.lazyPut(() => SharingController(), tag: 'mainhomepage');
}
}),
),
Please note I am using custome BottomNavigationBar => BottomNavyBar .. but the logic is same..
Thanks, Prakash
I am also using bottomNavigation and Get can't find controller for my GetView extended page:
// Controller page
class ProfileController extends GetxController {
final text= 'example text';
}
// View Page
class ProfileView extends GetView<ProfileController> {
@override
Widget build(BuildContext context) {
return Container(child: Text(controller.text));
}
// route config
GetPage(
name: Routes.PROFILE,
page: () => ProfileView(),
binding: ProfileBinding(),
),
//route name
abstract class Routes {
static const PROFILE = '/profile';
}
//binding
class ProfileBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<ProfileController>(
() => ProfileController(),
);
}
}
This code returns this error:
"ProfileController" not found. You need to call "Get.put(ProfileController())" or "Get.lazyPut(()=>ProfileController())"
I am using the same configuration in other places of my code as well. Those pages are not connected with BottomNavigation, and Get is able to find controller for them just fine. But the above profile page is navigated to using bottomNavigation.
Somehow lazyPut() did not work for me. I had to use put() instead and its working fine.. don't know how costly it would be in memory size..
@ZenMittal see an example here: https://github.com/jonataslaw/getx/issues/799#issuecomment-730719165
I have exactly the same problem, which occurs in the following (very simplified) scenario.
I have a Products
widget that looks like this and is included in two separate page widgets
class Products extends StatelessWidget {
final String someParam;
Products({this.someParam = 'foo'});
@override
Widget build(BuildContext context) {
return GetBuilder<ProductsController>(
init: ProductsController(),
builder: (controller) {
return ProductList();
});
}
}
class ProductList extends GetView<ProductsController> {
return Text(controller.anotherParam);
}
Then I have 2 Page
widgets which look like this
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder(
init: Page1Controller(),
builder: (controller) {
return Products(someParam: 'bar');
},
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder(
init: Page2Controller(),
builder: (controller) {
return Products(someParam: 'foo');
},
);
}
}
The problem occurs when switching pages
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder(
init: AppController(),
builder: (controller) {
if(controller.page == 1) {
return Page1();
} else {
return Page2();
}
},
);
}
}
[GETX] "AppController" has been initialized
[GETX] "Page1Controller" has been initialized
[GETX] "ProductsController" has been initialized
hot-reload works fine!
now, switch to Page2
[GETX] "Page2Controller" has been initialized
[GETX] "ProductsController" onClose() called
[GETX] "ProductsController" deleted from memory
[GETX] "Page1Controller" onClose() called
[GETX] "Page1Controller" deleted from memory
hot-reload gives the following error:
"ProductsController" not found. You need to call "Get.put(ProductsController())"
Notice, how another [GETX] "ProductsController" has been initialized is missing here
switch back to Page1
[GETX] "Page1Controller" has been initialized
[GETX] "ProductsController" has been initialized
[GETX] "Page2Controller" onClose() called
[GETX] "Page2Controller" deleted from memory
hot-reload works fine
The ProductsController
is not inited when switching to Page2
, and therefore gives an error.
When preventing ProductsController
from removing with autorRemove: false
, this (obviosly) does not trigger the onInit()
of ProductsController
anymore, when switching pages.
I could get the ProductsController
re-initilized when I render Products
after the PageXController
adds a delay of 1 second to the rendering-process.
PageXController.dart
onInit() {
setBusy(true);
update();
Future.delayed(Duration(milliseconds: 1000), () {
setBusy(false);
update();
});
super.onInit();
}
Page.dart
return controller.isBusy
? Text('Test')
: Products(someParam: 'foo');
After fiddling around I finally found the solution.
So, to use GetView
propperly, you have to init the corresponding controller with a tag, and pass that tag to your Widget.
class Products extends StatelessWidget {
final String someParam;
Products({this.someParam = 'foo'});
@override
Widget build(BuildContext context) {
return GetBuilder<ProductsController>(
init: ProductsController(),
tag: 'tag-$someParam'
builder: (controller) {
return ProductList('tag-$someParam');
});
}
}
class ProductList extends GetView<ProductsController> {
final String ctag;
ProductList (this.ctag);
@override
String get tag => ctag;
Widget build(BuildContext context) {
return Text(controller.anotherParam);
}
}
If done right you should see outputs like these
[GETX] "ProductsControllertag-foo" has been initialized
[GETX] "ProductsControllertag-foo" onClose() called
[GETX] "ProductsControllertag-foo" deleted from memory
[GETX] "ProductsControllertag-bar" has been initialized
...
[GETX] Instance "ProductRepoController" has been created [GETX] Instance "PopularProductRepo" has been created [GETX] Instance "ApiClient" has been created [GETX] Instance "ApiClient" has been initialized [GETX] Instance "PopularProductRepo" has been initialized [GETX] Instance "RecommendedProductRepo" has been created [GETX] Instance "RecommendedProductRepo" has been initialized [GETX] Instance "ProductRepoController" has been initialized [GETX] Instance "GetMaterialController" has been created [GETX] Instance "GetMaterialController" has been initialized [GETX] GOING TO ROUTE / [GETX] Instance "CartRepoController" has been created [GETX] Instance "CartRepo" has been created [GETX] Instance "SharedPreferences" has been created [GETX] Instance "CartRepoController" has been initialized [GETX] Instance "UserRepoController" has been created [GETX] Instance "UserRepo" has been created [GETX] Instance "UserRepoController" has been initialized [GETX] Instance "LocationRepoController" has been created [GETX] Instance "LocationRepo" has been created [GETX] Instance "LocationRepoController" has been initialized [GETX] REPLACE ROUTE / [GETX] NEW ROUTE /foodPage?pageId=0 [GETX] "SharedPreferences" deleted from memory [GETX] "CartRepo" deleted from memory [GETX] "CartRepoController" onDelete() called [GETX] "CartRepoController" deleted from memory [GETX] "UserRepo" deleted from memory [GETX] "LocationRepo" deleted from memory
I'am using the GetX pattern using get_cli so for all pages I'm using bindings to inject my controllers. It works fine but when I change something in my code and save it vscode applies hot reload in that moment the controller of my current page is deleted from memory so I need reload the app to taste my new changes
Flutter Version: 1.22.2
Getx Version: 3.15.0
Describe on which device you found the bug: Pixel 3a API 30 - Android Emulator.
Minimal reproduce code
My pages
Binding
my view
home controller
THANKS FOR THE ASWER