Flutter框架篇:GetxController原理深度解析!!!!
创始人
2024-12-28 06:10:05
0

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

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

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

1.Get.lazyPut(() => XXXController());
2.Get.putAsync(() => XXXController());
3.Get.create(() => XXXController());
4.Get.put(() => XXXController());

原理解析及使用场景

//延迟初始化,只有在调用Get.find()的时候才会创建controller void 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的原理比较复杂,详细看下一章节。

相关内容

热门资讯

四分钟了解(微扑克模拟器)外挂... 四分钟了解(微扑克模拟器)外挂辅助器插件(微扑克)辅助器ai技术(2025已更新)(哔哩哔哩)四分钟...
七分钟了解!WPK开发(WpK... 七分钟了解!WPK开发(WpK)透视辅助!(透视辅助)详细教程(2023已更新)(哔哩哔哩);AI智...
一分钟了解wpk德州测试外挂(... 自定义新版wpk系统规律,只需要输入自己想要的开挂功能,一键便可以生成出wpk专用辅助器,不管你是想...
必备攻略wpk微扑克有挂的(辅... 必备攻略wpk微扑克有挂的(辅助透视)软件透明挂(2024已更新)(哔哩哔哩);超受欢迎的微扑克稳赢...
2分钟了解《WPK辅助透视》W... 您好,WPK这款游戏可以开挂的,确实是有挂的,需要了解加微【439369440】很多玩家在这款游戏中...
带你了解(微扑克规律)外挂辅助... 您好,微扑克这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家在这款游戏中...
专业讨论《Wepoke开挂》软... 专业讨论《Wepoke开挂》软件透明挂!(辅助挂)外挂透明挂系统(2020已更新)(哔哩哔哩);德扑...
六分钟了解!情怀手机麻将辅牌器... 六分钟了解!情怀手机麻将辅牌器购买!(透视)外挂辅助器开挂(2021已更新)-哔哩哔哩详细攻略(小薇...
第1个科普微扑克ai辅助(辅助... 第1个科普微扑克ai辅助(辅助挂)软件透明挂(2024已更新)(哔哩哔哩);AI智能教程细节普及微扑...
科技通报一乐麻将有挂的(辅助挂... 科技通报一乐麻将有挂的(辅助挂)太坑了其实真的是有挂(2024已更新)(哔哩哔哩)科技通报一乐麻将有...