GetsControllers是否会自动关闭obs流? [英] Are obs stream being closed automatically by GetxControllers?

查看:245
本文介绍了GetsControllers是否会自动关闭obs流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下软件包

该应用程序通过3种方式使用Get Controllers拥有一个HomePage和3个ChildPages,所有这些都将其从内存中删除:

  1. GetX/GetBuilder
  2. Get.put
  3. 绑定

  import'package:flutter/material.dart';导入'package:get/get.dart';void main(){//MyCounterBinding().dependencies();//通常在绑定发生的地方runApp(MyApp());}MyApp类扩展了StatelessWidget {@override窗口小部件build(BuildContext context){返回GetMaterialApp(标题:"GetX Dispose Ex",主页:HomePage(),);}}HomePage扩展StatelessWidget {@override窗口小部件build(BuildContext context){返回脚手架(appBar:AppBar(标题:Text('GetX Dispose Test'),),身体:中心(子:列(mainAxisAlignment:MainAxisAlignment.space孩子们: [加高按钮(子代:Text('GetX/Builder Child'),onPressed:()=>Get.to(ChildPage()),),加高按钮(子代:Text('Get.put Child'),onPressed:()=>Get.to(ChildPutPage()),),加高按钮(子代:Text('Binding Child'),onPressed:()=>Get.to(ChildBindPage()),),],),),);}}///GETX/GETBUILDER///在获取"小部件中创建控制器ChildPage类扩展StatelessWidget {@override窗口小部件build(BuildContext context){返回脚手架(appBar:AppBar(标题:Text('GetX Dispose Test Counter'),),身体:中心(子:列(mainAxisAlignment:MainAxisAlignment.space孩子们: [文字(这是子页面"),GetX< ChildX>(初始化:ChildX(),生成器:(cx)=>Text('Counter:$ {cx.counter}',style:TextStyle(fontSize:20),),),GetBuilder< ChildX>(初始化:ChildX(),生成器:(cx)=>加高按钮(子级:Text('Increment'),onPressed:cx.inc,),),],),),);}}///GET.PUT///在构建时创建Controller实例,可在小部件构建上下文中的任何位置使用ChildPutPage类扩展StatelessWidget {//最终的ChildX cx = Get.put(ChildX());//错误的放置位置//参见https://github.com/jonataslaw/getx/issues/818#issuecomment-733652172@override窗口小部件build(BuildContext context){final ChildX cx = Get.put(ChildX());返回脚手架(appBar:AppBar(标题:Text('GetX Dispose Test Counter'),),身体:中心(子:列(mainAxisAlignment:MainAxisAlignment.space孩子们: [文字(这是子页面"),Obx(()=>Text('Counter:$ {cx.counter}',style:TextStyle(fontSize:20),),),加高按钮(子级:Text('Increment'),onPressed:cx.inc,)],),),);}}类MyCounterBinding扩展了Bindings {@override无效的dependencies(){Get.lazyPut(()=> ChildX(),fenix:true);}}///获取绑定///通常,MyCounterBinding().dependencies()调用是在main()中完成的,///使它在整个应用程序中都可用.///将根据需要创建/删除/重新创建lazyPut控制器/w [fenix:true]或///由SmartManagement设置指定.///但是为了防止Bindings污染其他示例,它已在此示例中完成///小部件的构建上下文(通常不会这样做.)ChildBindPage类扩展StatelessWidget {@override窗口小部件build(BuildContext context){MyCounterBinding().dependencies();//仅用于说明/示例返回脚手架(appBar:AppBar(标题:Text('GetX Dispose Test Counter'),),身体:中心(子:列(mainAxisAlignment:MainAxisAlignment.space孩子们: [文字(这是子页面"),Obx(()=>Text('Counter:$ {ChildX.i.counter}',style:TextStyle(fontSize:20),),),加高按钮(子级:Text('Increment'),onPressed:ChildX.i.inc,)],),),);}}ChildX类扩展GetxController {静态ChildX get i =>Get.find();RxInt计数器= 0.obs;void inc()=>counter.value ++;} 

注释

Get.to与Navigator.push

在子窗口小部件中使用 Get.put()时,请确保您正在使用 Get.to()导航到该子窗口,而不是Flutter的内置窗口. Navigator.push .

当使用 Get.to 时,

GetX将目标窗口小部件包装在 GetPageRoute 中.导航/将小部件弹出堆栈时,此Route类将在此路由中处理Controller.如果使用 Navigator.push ,则不会涉及GetX,并且不会获得此自动清除.

Navigator.push

  onPressed:()=>Navigator.push(上下文,MaterialPageRoute(生成器:(上下文)=>ChildPutPage())), 

获取地址

  onPressed:()=>Get.to(ChildPutPage()), 

I am using the following package https://pub.dev/packages/get. Do I need to close my .obs in the onClose of a GetxController? I can't find anything about this in the docs. And looking at my memory it appears that the are being destroyed automatically.

解决方案

In my understanding of GetX + Flutter so far...

No, you shouldn't have to remove .obs in the close() method of GetxControllers. Disposal of observables from a Controller are done automatically when the Controller is removed from memory.

GetX disposes/removes GetxControllers (and their observables) when the widget in which they are contained are popped off the widget stack / removed from the widget tree (by default, but can be overridden).

You can see this in the override of dispose() methods of various Get widgets.

Here's a snippet of dispose() that's run when GetX widgets are popped/removed:

  @override
  void dispose() {
    if (widget.dispose != null) widget.dispose(this);
    if (isCreator || widget.assignId) {
      if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
        GetInstance().delete<T>(tag: widget.tag);
      }
    }
    subs.cancel();
    _observer.close();
    controller = null;
    isCreator = null;
    super.dispose();
  }

When you use Bindings or Get.to() you're using GetPageRoute's which do cleanup by Route names:

  @override
  void dispose() {
    if (Get.smartManagement != SmartManagement.onlyBuilder) {
      WidgetsBinding.instance.addPostFrameCallback((_) => GetInstance()
          .removeDependencyByRoute("${settings?.name ?? routeName}"));
    }
    super.dispose();
  }

Test App

Below is a test App you can copy/paste into Android Studio / VSCode and run to watch the debug or run window output for GETX lifecycle events.

GetX will log the creation & disposal of Controllers in and out of memory.

The app has a HomePage and 3 ChildPages using Get Controllers in 3 ways, all which remove itself from memory:

  1. GetX / GetBuilder
  2. Get.put
  3. Bindings

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

void main() {
  // MyCounterBinding().dependencies(); // usually where Bindings happen
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'GetX Dispose Ex',
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GetX Dispose Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            RaisedButton(
              child: Text('GetX/Builder Child'),
              onPressed: () => Get.to(ChildPage()),
            ),
            RaisedButton(
              child: Text('Get.put Child'),
              onPressed: () => Get.to(ChildPutPage()),
            ),
            RaisedButton(
              child: Text('Binding Child'),
              onPressed: () => Get.to(ChildBindPage()),
            ),
          ],
        ),
      ),
    );
  }
}

/// GETX / GETBUILDER
/// Creates Controller within the Get widgets
class ChildPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GetX Dispose Test Counter'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Text('This is the Child Page'),
            GetX<ChildX>(
              init: ChildX(),
              builder: (cx) => Text('Counter: ${cx.counter}', style: TextStyle(fontSize: 20),),
            ),
            GetBuilder<ChildX>(
              init: ChildX(),
              builder: (cx) => RaisedButton(
                child: Text('Increment'),
                onPressed: cx.inc,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/// GET.PUT
/// Creates Controller instance upon Build, usable anywhere within the widget build context
class ChildPutPage extends StatelessWidget {
  //final ChildX cx = Get.put(ChildX()); // wrong place to put  
  // see https://github.com/jonataslaw/getx/issues/818#issuecomment-733652172

  @override
  Widget build(BuildContext context) {
    final ChildX cx = Get.put(ChildX());
    return Scaffold(
      appBar: AppBar(
        title: Text('GetX Dispose Test Counter'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Text('This is the Child Page'),
            Obx(
              () => Text('Counter: ${cx.counter}', style: TextStyle(fontSize: 20),),
            ),
            RaisedButton(
              child: Text('Increment'),
              onPressed: cx.inc,
            )
          ],
        ),
      ),
    );
  }
}

class MyCounterBinding extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => ChildX(), fenix: true);
  }
}

/// GET BINDINGS
/// Normally the MyCounterBinding().dependencies() call is done in main(),
/// making it available throughout the entire app.
/// A lazyPut Controller /w [fenix:true] will be created/removed/recreated as needed or
/// as specified by SmartManagement settings.
/// But to keep the Bindings from polluting the other examples, it's done within this
/// widget's build context (you wouldn't normally do this.)
class ChildBindPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    MyCounterBinding().dependencies(); // just for illustration/example

    return Scaffold(
      appBar: AppBar(
        title: Text('GetX Dispose Test Counter'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            Text('This is the Child Page'),
            Obx(
                  () => Text('Counter: ${ChildX.i.counter}', style: TextStyle(fontSize: 20),),
            ),
            RaisedButton(
              child: Text('Increment'),
              onPressed: ChildX.i.inc,
            )
          ],
        ),
      ),
    );
  }
}


class ChildX extends GetxController {
  static ChildX get i => Get.find();
  RxInt counter = 0.obs;

  void inc() => counter.value++;
}

Notes

Get.to vs. Navigator.push

When using Get.put() in a child widget be sure you're using Get.to() to navigate to that child rather than Flutter's built-in Navigator.push.

GetX wraps the destination widget in a GetPageRoute when using Get.to. This Route class will dispose of Controllers in this route when navigating away / popping the widget off the stack. If you use Navigator.push, GetX isn't involved and you won't get this automatic cleanup.

Navigator.push

onPressed: () => Navigator.push(context, MaterialPageRoute(
                  builder: (context) => ChildPutPage())),

Get.to

onPressed: () => Get.to(ChildPutPage()),

这篇关于GetsControllers是否会自动关闭obs流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆