本文更新非常频繁,最新内容请查看:最新内容—GetX代码生成IDEA插件功能说明
本文章不是写getx框架的使用,而且其代码生成IDEA插件的功能讲解
我之前写过俩篇很长很长的getx文章
一篇入门使用:Flutter GetX使用—简洁的魅力!
一篇原理深度剖析:Flutter GetX深度剖析 | 我们终将走出自己的路(万字图文)
鱼和渔都已经交给大家了,就没必要去赘述了
同时,我也写了一个getx代码生成插件:getx_template,这个工具相当于钓鱼座椅(让你更舒服的钓鱼或吃鱼?)吧!初期功能十分简单,就是生成单页面相应的模块代码,连个记忆选项功能都没有,基本上就是个塑料座椅的程度
兄弟们,我实在不想写水文;但是这个工具一个功能按钮,改变的代码可能很少,其背后所蕴含的东西,可能需要大量的笔墨去描述,这边就统一的和各位彦祖于宴亦菲们,说道说道。
本文长期更新,如果想知道插件每次详细更新内容,可以点进来看。
鄙人是个十足的颜值党,这次最新版本的页面,我做了很多考量
首页随着各位靓仔提的各种需求,Select Function,从最初的俩个功能,增加到现在的七个功能
基于上述的思考,我绞尽脑汁的想解决这个问题
这次我全面的改善了dialog布局问题
这一次,在48寸的屏幕上,肯定不会出现下面这种情况了
虽然我没试,但是我对自己的代码有信心
这里提供俩种大的模式选择:default,easy
来看下区别
default模式
class TestPage extends StatelessWidget {
final logic = Get.put(TestLogic());
final state = Get.find().state;
@override
Widget build(BuildContext context) {
return Container();
}
}
class TestLogic extends GetxController {
final TestState state = TestState();
}
class TestState {
TestState() {
///Initialize variables
}
}
Easy模式
class TestPage extends StatelessWidget {
final logic = Get.put(TestLogic());
@override
Widget build(BuildContext context) {
return Container();
}
}
class TestLogic extends GetxController {
}
总结
上面的default模式和easy模式,从代码上看,还是能看出很明显的区别
我曾写过一个比较复杂模块
除非是肉眼可见的业务极简模块,推荐使用Easy模块;其余的情况推荐使用Default模式
useFolder和usePrefix功能比较简单,这里就放在一起讲了
useFolder
本项功能是默认选中的,会在创建的多个文件外,创建一个文件夹,方便管理
usePrefix
一些小伙伴喜欢在各层:view,state,logic,前加上module名的前缀(小写+下划线)
这边也为大家提供了一个这样的可选功能
请注意:isPageView和autoDispose按钮不能同时选中,他们俩都能解决PageView中存的问题,选择其中一按钮,另一按钮会自动取消勾选
这算是一个非常有用的功能了
如果大家在PageView中使用getx,可能会发现,所有的子页面中的GetXController,一下全被注入了!并不是切换到对应页面,注入对应的GetXController!
PageView(children: [
FunctionPage(),
ExamplePage(),
SettingPage(),
])
分析
我们可以来分析下,为什么会发生这种情况,来看下:FunctionPage
class FunctionPage extends StatelessWidget {
final logic = Get.put(TestLogic());
final state = Get.find().state;
@override
Widget build(BuildContext context) {
return Container();
}
}
我们注入的步骤,是放在类的成员变量作用域
PageView触发机制
有了上面这层理解,就很容易解决PageView的问题了
处理
所以此功能只需要改变View文件里,GetXController的注入位置,其它文件不需要变动
binding是为了统一管理GetXController,来看下binding和非binding的区别
非Binding
class TestOnePage extends StatelessWidget {
final logic = Get.put(TestOneLogic());
@override
Widget build(BuildContext context) {
return Container();
}
}
class TestOneLogic extends GetxController {
}
Binding:需要配套GetX路由
class TestTwoBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => TestTwoLogic());
}
}
class TestTwoPage extends StatelessWidget {
final logic = Get.find();
@override
Widget build(BuildContext context) {
return Container();
}
}
class TestTwoLogic extends GetxController {
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
initialRoute: RouteConfig.testOne,
getPages: RouteConfig.getPages,
);
}
}
class RouteConfig {
static const String testTwo = "/testTwo";
static final List getPages = [
GetPage(
name: testTwo,
page: () => TestTwoPage(),
binding: TestTwoBinding(),
),
];
}
总结
binding文件里面,使用的是懒注入:在使用了find方法的时候,才会真正的注入
所以在view里面,就需要将put改成find就行了,总结下
这是个非常简单的功能,就放在次要功能tab下
一些小伙伴,logic模块需要经常写onReady和onClose回调,懒得每次手写;所以在插件里添加了自动补上这俩个回调的功能
该功能正如名字一样:自动释放GetXController
实际上,这是个非常重要的功能,但是实现的太不优雅了,就把它移到了次要功能tab里面了
GetX内部对回收GetXController,做了很多处理,释放的操作是在GetX路由处理的;但是,业务多变复杂,导致某些GetXController很难被框架自动释放,例如:
上面的这些情况都无法自动回收GetXController;为此,我在插件里,给出了一个解决方案,区别只在view文件
通用解决方案
class TestTwoPage extends StatefulWidget {
@override
_TestTwoPageState createState() => _TestTwoPageState();
}
class _TestTwoPageState extends State {
final logic = Get.put(TestTwoLogic());
@override
Widget build(BuildContext context) {
return Container();
}
@override
void dispose() {
Get.delete();
super.dispose();
}
}
class TestTwoLogic extends GetxController {
}
上面这种方案,是基本都能解决回收GetXController问题(除非你手动开启保活GetXController的参数)
但是!这里面需要使用StatefulWidget!多了很多代码!这太不优雅了!
优化解决方案
上面的是个通用解决方法,你不需要额外的引入任何其它的东西;但是这种方案用到了StatefulWidget,代码多了一大坨,让我有点膈应
鄙人有着相当的强迫症,想了很久
本来是想GetBuilder写个回收逻辑,然后提个PR给作者
那只能从外部入手,我就写了一个通用控件,来对相应的GetXController进行回收
GetBindWidget
import 'package:flutter/material.dart';
import 'package:get/get.dart';
/// GetBindWidget can bind GetxController, and when the page is disposed,
/// it can automatically destroy the bound related GetXController
///
///
/// Sample:
///
/// class SampleController extends GetxController {
/// final String title = 'My Awesome View';
/// }
///
/// class SamplePage extends StatelessWidget {
/// final controller = SampleController();
///
/// @override
/// Widget build(BuildContext context) {
/// return GetBindWidget(
/// bind: controller,
/// child: Container(),
/// );
/// }
/// }
class GetBindWidget extends StatefulWidget {
const GetBindWidget({
Key? key,
this.bind,
this.tag,
this.binds,
this.tags,
required this.child,
}) : assert(
binds == null || tags == null || binds.length == tags.length,
'The binds and tags arrays length should be equal\n'
'and the elements in the two arrays correspond one-to-one',
),
super(key: key);
final GetxController? bind;
final String? tag;
final List? binds;
final List? tags;
final Widget child;
@override
_GetBindWidgetState createState() => _GetBindWidgetState();
}
class _GetBindWidgetState extends State {
@override
Widget build(BuildContext context) {
return widget.child;
}
@override
void dispose() {
_closeGetXController();
_closeGetXControllers();
super.dispose();
}
///Close GetxController bound to the current page
void _closeGetXController() {
if (widget.bind == null) {
return;
}
var key = widget.bind.runtimeType.toString() + (widget.tag ?? '');
GetInstance().delete(key: key);
}
///Batch close GetxController bound to the current page
void _closeGetXControllers() {
if (widget.binds == null) {
return;
}
for (var i = 0; i < widget.binds!.length; i++) {
var type = widget.binds![i].runtimeType.toString();
if (widget.tags == null) {
GetInstance().delete(key: type);
} else {
var key = type + (widget.tags?[i] ?? '');
GetInstance().delete(key: key);
}
}
}
}
/// 回收单个GetXController
class TestPage extends StatelessWidget {
final logic = Get.put(TestLogic());
@override
Widget build(BuildContext context) {
return GetBindWidget(
bind: logic,
child: Container(),
);
}
}
/// 回收多个GetXController
class TestPage extends StatelessWidget {
final logicOne = Get.put(TestLogic(), tag: 'one');
final logicTwo = Get.put(TestLogic());
final logicThree = Get.put(TestLogic(), tag: 'three');
@override
Widget build(BuildContext context) {
return GetBindWidget(
binds: [logicOne, logicTwo, logicThree],
tags: ['one', '', 'three'],
child: Container(),
);
}
}
/// 回收日志
[GETX] Instance "TestLogic" has been created with tag "one"
[GETX] Instance "TestLogic" with tag "one" has been initialized
[GETX] Instance "TestLogic" has been created
[GETX] Instance "TestLogic" has been initialized
[GETX] Instance "TestLogic" has been created with tag "three"
[GETX] Instance "TestLogic" with tag "three" has been initialized
[GETX] "TestLogicone" onDelete() called
[GETX] "TestLogicone" deleted from memory
[GETX] "TestLogic" onDelete() called
[GETX] "TestLogic" deleted from memory
[GETX] "TestLogicthree" onDelete() called
[GETX] "TestLogicthree" deleted from memory
总结
对于上面的优化方案
唯一麻烦的:需要你手动把GetBindWidget这个控件,引入到自己的项目中
pub:lint库
这个功能,乍一看,大家估计都懵逼了;这要不是我写的,我看了也懵逼啊
但是,这个功能,真是少部分强迫症患者的福音
因为getx作者,在demo项目里面,引入的lint库,一些小伙伴可能也用了这个库
lint是一个严格规则的代码库,对于代码相应不规范的地方,会通过IDEA给与提示;对于我们很多认为合理的代码,有时候可能也会给出相应的警告
选中lintNorm按钮,就会以下面这种形式生成模板代码;所以说这个功能是强迫症患者福音。。。
对于用lint这种强规则的人,我表示:
pub:flutter_lints
最近Flutter在新建项目里面,默认加上了flutter_lints这个库,这个库的规则宽松很多,规则基本也是规范flutter的写法
当你开启lintNorm,也会帮你补上生成页面的构造函数
该功能提供了切换模板命名的操作
提供三套模板命名,只提供三套,不会再多增了
内部对持久化模块进行了重构
为什么要提供切换模板命名的功能?
当业务逐渐的复杂,很多时候,复杂的通用组件,也可以使用getx去封装
插件窗口增加三套模板切换
三套模板命名都支持自定义修改
示例
看下代码
class TestComponent extends StatelessWidget {
final logic = Get.put(TestLogic());
@override
Widget build(BuildContext context) {
return Container();
}
}
class TestLogic extends GetxController {
}
这是一个非常好用的功能
目前支持四种Wrap Widget类型:GetBuilder,GetBuilder(autoDispose),Obx,GetX
使用注意事项:鼠标点击在Widget上即可,然后按 alt+enter;请勿双击选中Widget名字
插件也为大家提供了,输入关键字生成快键代码片段的功能
请注意:关键字前缀为getx
还有其它的一些快捷代码,自行感受喽~~
3.2.x
3.1.x
3.0.x
2.1.x
1.5.x
1.3.x
1.2
1.1
1.0
在不断完善这个插件的时候,也是我不断思考的一个过程,
感谢大家提的各种蛋痛的需求
能让这个插件一点点的完善,以至于现在,,能真正的帮助靓仔们节省一点开发时间
系列文章 + 相关地址
插件的Github地址:getx_template
Flutter GetX使用—简洁的魅力!
Flutter GetX深度剖析 | 我们终将走出自己的路(万字图文)