小工具知识网

当前位置: 首页 > 行业知识 > Flutter框架篇:GetxController原理深度解析!!!!

行业知识

Flutter框架篇:GetxController原理深度解析!!!!

2026-11-02 18:14:31 来源:互联网转载

GetxController原理深度解析----万字图解!!!!

getx是flutter开发中使用最频繁也最受欢迎的开发框架,要使用它必须先掌握其原理,并利用其提供的工具,达到更好的利用框架的目的,在了解原理的同时在结合设计模式去分析,不仅能学到原理,还能加强设计模式的学习

一、GetxController的不同创建方式和使用场景

1.Get.lazyPut(() => XXXController());

2.Get.putAsync(() => XXXController());

3.Get.create(() => XXXController());

4.Get.put(() => XXXController());

原理解析及使用场景

//延迟初始化,只有在调用Get.find()的时候才会创建controllervoid lazyPut(//函数方式创建,懒加载    InstanceBuilderCallback builder, {    //对builder内容进行标记    String? tag,    //是否持久化保存controller    bool? fenix,    bool permanent = false,  }) {    _insert(      isSingleton: true,      name: tag,      permanent: permanent,      builder: builder,      fenix: fenix ?? Get.smartManagement == SmartManagement.keepFactory,    );  }  void create(  //函数方式创建,懒加载    InstanceBuilderCallback builder, {    String? tag,    bool permanent = true,  }) {    _insert(      isSingleton: false,      name: tag,      builder: builder,      permanent: permanent,    );  }     S put(   //直接创建    S dependency, {    String? tag,    bool permanent = false,    @deprecated InstanceBuilderCallback? builder,  }) {    _insert(        isSingleton: true,        name: tag,        permanent: permanent,        builder: builder ?? (() => dependency));    return find(tag: tag);  }

1.tag(可选):如果想要创建相同类型的controller(由于controller只会创建一次,就像单例,

如果想创建多个,则用tag做标记)

2.permanent(可选):默认情况下,get会在实例不再使用后销毁(例如,一个已经销毁的视图controller),如果需要实例

在整个生命周期中都存在,则设为true。

3.fenix(可选):下次使用时是否重建,当不使用时,实例会被丢弃,但当再次需要使用时,Get会重新创建实例

就像 bindings api 中的 "SmartManagement.keepFactory "一样。

4.isSingleton(不可选):是否是单例形式存储。如果为true则直接调用builder回调,false则先使用dependency直接创建的实例,如果不存在则调用回调函数创建实例。

1.lazyPut 懒加载,传回调函数,只有在调用Get.find()的时候才会调用回调函数创建实例(跟随widget生命周期变化)

2.putAsync 异步实例创建,比如sharePreference.(跟随widget生命周期变化)

3.create 传入的permanent为true,持久化保存实力,不随生命周期变化

4.put 普通创建实例(跟随widget生命周期变化)

二、GetxController的实例获取与使用

  //如果是用create创建的controller则调用此方法每次都会重新创建实例  //如果注册的是controller,则会初始化它的生命周期  S find({String? tag}) {  //通过tag标记寻找已保存的controller(如果没有的话通过controller的类名寻找)    final key = _getKey(S, tag);    //判断是否注册过,注册过则直接获取controller实例的包装类_InstanceBuilderFactory    if (isRegistered(tag: tag)) {      final dep = _singl[key];      if (dep == null) {        if (tag == null) {          throw 'Class "$S" is not registered';        } else {          throw 'Class "$S" with tag "$tag" is not registered';        }      }      //关注此函数      final i = _initDependencies(name: tag);      return i ?? dep.getDependency() as S;    } else {      // ignore: lines_longer_than_80_chars      throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';    }  }

上面的代码比较简单,就是从容器中获取controller实例,我们重点看看_initDependencies(name: tag);

 S? _initDependencies({String? name}) {    final key = _getKey(S, name);    final isInit = _singl[key]!.isInit;    S? i;    //第一次执行会走进来,因为isInit默认为false    if (!isInit) {      i = _startController(tag: name);      if (_singl[key]!.isSingleton!) {        _singl[key]!.isInit = true;        if (Get.smartManagement != SmartManagement.onlyBuilder) {          RouterReportManager.reportDependencyLinkedToRoute(_getKey(S, name));        }      }    }    return i;  }  /// 真正的初始化controller的逻辑  S _startController({String? tag}) {    final key = _getKey(S, tag);    final i = _singl[key]!.getDependency() as S;    if (i is GetLifeCycleBase) {      //开始执行controller的生命周期      //oninit --- 并同时监听onReady执行(界面布局完成后)      i.onStart();      if (tag == null) {        Get.log('Instance "$S" has been initialized');      } else {        Get.log('Instance "$S" with tag "$tag" has been initialized');      }      if (!_singl[key]!.isSingleton!) {        RouterReportManager.appendRouteByCreate(i);      }    }    return i;  }  // 说明只执行一次onInit();初始化  void _onStart() {    if (_initialized) return;    onInit();    _initialized = true;  }

上面的代码只有一个逻辑,就是执行controller的生命周期函数

abstract class DisposableInterface extends GetLifeCycle {  //当调用Get.find()的时候执行此方法。  @override  @mustCallSuper  void onInit() {    super.onInit();//这里开始监听当前页面的vsync信号帧绘制,绘制完成后回调onReady()方法    Get.engine.addPostFrameCallback((_) => onReady());  }  /// Called 1 frame after onInit(). It is the perfect place to enter  /// navigation events, like snackbar, dialogs, or a new route, or  /// async request.  @override  void onReady() {  //这里需要客户端进行重写    super.onReady();  }

1.onInit只会执行一次,调用find的时候会首先调用生命周期onInit方法

2.根据vsync信号刷新回调onReady生命周期方法。即界面构建完成之后调用

总结:只有controller在当前页面使用Get.find()的时候。首先会执行onInit方法。如果在widget中调用,同时还会监听页面绘制完成并调用onReady方法。

注意:如果只是通过Get.find()的方式获取controller,并不会调用controller的delete()方法清空内存。需要手动调用Get.delete()方法从内存中清除controller。

三、GetxController的销毁时机

1.在widget的dispose()中手动调用Get.delete()清除controller

2.绑定widget生命周期,跟随widget生命周期清除

getx提供了多个widget供开发者使用。其中有下列常用的几种

负责管理controller的widget

1.GetView(具有自动获取controller的功能)

 class AwesomeController extends GetxController {   final String title = 'My Awesome View'; } class AwesomeView extends GetView {   /// 如果要给controller做个标记的话可以这么写   /// Get.find(tag:"myTag");   @override  final String tag = "myTag";   AwesomeView({Key key}):super(key:key);   @override   Widget build(BuildContext context) {     return Container(       padding: EdgeInsets.all(20),       child: Text( controller.title ),     );   } }

2.GetWidget(缓存controller)

内部跟着缓存走,须使用Get.create(()=>Controller());(因为getWidget适用于保存同一类controller的不同实例。),所以每次都需要调用创建方法。在其从内存中退出时,如widget从数中卸载时,会自动调用onclose对controller进行销毁

部分源码解析

@override  void onClose() {    if (_isCreator) {    //异步调用controller的销毁逻辑      Get.asap(() {        widget!.controller!.onDelete();        Get.log('"${widget!.controller.runtimeType}" onClose() called');        Get.log('"${widget!.controller.runtimeType}" deleted from memory');        GetWidget._cache[widget!] = null;      });    }    info = null;    super.onClose();  }

在widget即将销毁时,会判断是否是通过create创建的controller,如果是则执行销毁缓存controller的方法。

以下是使用方式

class GetViewAndGetWidgetExample extends GetWidget {  @override  Widget build(BuildContext context) {    Get.create(() => GetViewCountController());    return Scaffold(      appBar: AppBar(        title: Text("GetX GetView"),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          crossAxisAlignment: CrossAxisAlignment.center,          children: [            Obx(() => Text(              "count的值为:  ${controller?.count}",              style: TextStyle(                color: Colors.red,                fontSize: 30              ),            )),            SizedBox(height: 20,),            ElevatedButton(              onPressed: () {                controller.increment();              },              child: Text("点我加1"))          ],        ),      ),    );  }}

getwidget用的比较少,一般都是用的getview

2.GetResponsiveView (平板,桌面等适配)

负责状态管理的widget(StatefulWidget类,具有状态管理功能)

1.GetBuilder(相比getx多了id和filter的变量)

2.GetX

3.Obx

1.从使用性能看,GetBuilder是性能最好的工具,需要手动调用update()进行更新

2.obx比较常用,只有初始化变量后就可以响应式更新

3.Getx是结合了obx和Getbuilder的功能,比较消耗内存。

一 .GetBuilder原理解析

部分源码截取

@override  void initState() {    // _GetBuilderState._currentState = this;    super.initState();    //初始化GetBuilder的时候可以传入initState进行初始化操作。    widget.initState?.call(this);    var isRegistered = GetInstance().isRegistered(tag: widget.tag);//global默认为true,即为全局controller。可在当前widget或全局使用    if (widget.global) {      if (isRegistered) {        if (GetInstance().isPrepared(tag: widget.tag)) {          _isCreator = true;        } else {          _isCreator = false;        }        //如果注册过则通过find的方式获取controller        controller = GetInstance().find(tag: widget.tag);      } else {      //如果未注册过,则先调用传入的init初始化controller。      //类似下图      //GetBuilder(        //init: MusicSetController(),        //builder: (_) {        controller = widget.init;        _isCreator = true;        //将controller放进缓存中        GetInstance().put(controller!, tag: widget.tag);      }    } else {      //如果非全局,则直接初始化并调用controller的onstart方法。      controller = widget.init;      _isCreator = true;      controller?.onStart();    }    if (widget.filter != null) {      _filter = widget.filter!(controller!);    }//往下看    _subscribeToController();  }  //注册监听器,setstate((){});getUpdate就是setstate监听器。这里会将监听方法存起来,在手动调用  //refresh()或refreshGroup(id)的时候会调用监听器刷新,即setstate.  void _subscribeToController() {    _remove?.call();    _remove = (widget.id == null)        ? controller?.addListener(            _filter != null ? _filterUpdate : getUpdate,          )        : controller?.addListenerId(            widget.id,            _filter != null ? _filterUpdate : getUpdate,          );  }

1.getBiulder首先会先调用传入的initState初始化函数(如果传入的话)。

2.判断controller是否存在,如果存在则从缓存中获取,否则重新创建一个(从传入的init创建)。

3.注册监听器。只有在手动调用refresh或refreshGroup的时候会执行GetBuider的setstate方法进行刷新。

GetBuilder的销毁

@override  void dispose() {    super.dispose();    //首先调用手动传入的dispose方法。    widget.dispose?.call(this);    //判断是否创建过或者assignId是否为true。则调用销毁方法。一般_isCreator初始化的时候就为true了。    if (_isCreator! || widget.assignId) {      if (widget.autoRemove && GetInstance().isRegistered(tag: widget.tag)) {        GetInstance().delete(tag: widget.tag);      }    }    _remove?.call();    controller = null;    _isCreator = null;    _remove = null;    _filter = null;  }

GetBuilder使用方法

Widget build(BuildContext context) {    // TODO: implement build    return Material(      child: GetBuilder(      //如果首次使用,这个必传。需要进行初始化操作        init: MusicSetController(),        builder: (_) {          return Container();        },        //如要为了保证其执行销毁操作,可传入此参数。在widget销毁的时候,controller也会跟着销毁。        assignId: true,      ),

Obx使用方法。

@override  Widget build(BuildContext context) {RxInt count = 0.obx;    return Scaffold(      appBar: AppBar(        title: Text("GetX GetView"),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          crossAxisAlignment: CrossAxisAlignment.center,          children: [            Obx(() => Text(              "count的值为:  ${count.value}",              style: TextStyle(                color: Colors.red,                fontSize: 30              ),            )),            SizedBox(height: 20,),            ElevatedButton(              onPressed: () {                count ++;              },              child: Text("点我加1"))          ],        ),      ),    );  }

1.obx调用比较简单,只需要包裹一个使用count变量的widget

2.同时将count变量初始化成RxInt类型

3.使用变量的时候通过count.value调用即可。

4.如果count变量发生变化,则只刷新obx的widget

obx的原理比较复杂,详细看下一章节。

上一篇:自助建站建设怎么做?

下一篇:抖音评论赞购买秘籍,轻松获取高赞,成为人气王!