Flutter Package - Get_it

Get_it

Get_it是一个服务定位器,更通俗具体一点得说它是一个工具箱。借鉴于.net。

对于想偷懒,直接全局调用的某些对象尤其省事。配合Provider事半功倍

什么叫做工具箱

我们通过介绍如何使用Get_it来解释什么叫做工具箱。

比如,如果我是一个铁匠,工作的时候要使用锤子,那么我就从工具箱里面找出来锤子,如果我要用扳手,那么我也从工具箱中把我的扳手找出来。

Get_it在现实中得定位大致就是一个工具箱。要成为一个好用的工具箱,第一步得把各种各样得工具放进去,也就是

步骤一:在工具箱中注册工具

locator.dart


import 'package:get_it/get_it.dart';
import './core/services/navigation_service.dart';
import './core/services/service_jiandao.dart';
import './core/services/service_chuizi.dart';
import './core/services/service_C.dart';

GetIt locator = GetIt.instance;

Future<void> setupLocator({bool test = false}) async {
  /// Services 需要什么就注册什么
  // NavigationService 就是一个工具,导航工具
  /// 工具一:导航服务,注册(放入工具箱)
  locator.registerLazySingleton<NavigationService>(
    () => NavigationService(),
  );

  /// ......
  /// 工具二:剪刀,注册(放入工具箱)
  locator.registerLazySingleton<ServiceJiandao>(
    () => ServiceJiandao(),
  );
  /// 工具三:锤子,注册(放入工具箱)
  locator.registerLazySingleton<ServiceChuizi>(
    () => ServiceChuizi(),
  );
  /// 工具四:工具C,注册(放入工具箱)
  locator.registerLazySingleton<ServiceC>(
    () => ServiceC(),
  );
}

取名随意,不过最好命名为 Service + Name这样的形式。

工具箱里面先在已经装好了工具了,也不能把工具箱丢在荒郊野外,还需要把它放到我们工作室内。

也就是第二步,需要在入口文件 main.dart 启动一下,表示我已经把工具箱带到了工作室.

步骤二:将工具箱放入工作室

main.dart

void main() {

	/// 启动GetIt定位服务
	setupLocator();

	runApp(MyApp());

}

到了这一步,所有准备工作已经完成,工具箱已经准备好,并且已经被我们放入到工作室中,那么在工作打铁(写页面)得过程中就可以随意的使用了。

如何使用这些工具?

在页面得任何位置,都可以调用任何一个已经注册得工具,调用方式有以下几种,请自行类比:

// 调用工具一:导航服务
// push() 方法在 navigation_service.dart 中定义
FlatButton(
  child: Text("Update"),
  onPressed: (){
	locator<NavigationService>().push(RoutesUtils.homePage);
  }
),
// 调用工具二:剪刀 。其中 caijian() 方法在 service_jiandao.dart 中定义
GestureDetector(
  child: Text("Update"),
  onTap: (){
	locator<ServiceJiandao>().caijian();
  }
),
// 调用工具三:锤子。 其中 name 属性在 service_chuizi.dart 中定义
FlatButton(
  child: Text("Update"),
  onPressed: (){
  	var serverChuizi = locator<ServiceChuizi>();
	serverChuizi.name;
  }
),
// 调用工具四:工具C。kissMe() 方法在 service_C.dart 中定义
FlatButton(
  child: Text("Update"),
  onPressed: (){
  	var serverC = locator<ServiceC>();
	serverC.kissMe();
  }
),

那么剩下的内容就是如何创造工具,以及如何去写工具中的方法。这就跟普通dart的写法一模一样了。
如何创造工具?工具示例


Get_it | InheritedWidget | Provider 对比

使用get_it并不复杂,并且它还跟 InheritedWidget ,Provider 是同样的功能。那为什么要重复造轮子,意义在于:代替 InheritedWidget或Provider成为在widget中访问class最佳的工具

在我看来,这一点它做到了.

我们都知道 flutter项目的页面结构都是一个树状结构,上万层树干树杈嵌套也很正常,这三者都是为了解决树干与分支之间数据通信问题, 但是用于同一种功能的工具也有好坏精细之分

get_it 好用多了, 它直接上王八拳:工具一旦注册,那么全局随意调用。




以下内容为拓展阅读

下面列出了使用InheritedWidgetProvider 得使用方式,自行对比上面Get_it调用,看看哪种更简单灵活。

1. 对比使用:InheritedWidget

创建数据类 ShareDataWidget,然后在页面中用数据类ShareDataWidget包裹页面child部分

第一步,创建 ShareDataWidget.dart 文件

class ShareDataWidget extends InheritedWidget {
  ShareDataWidget({
    @required this.data,
    Widget child
  }) :super(child: child);
  final int data;
  static ShareDataWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<ShareDataWidget>();
  }
  @override
  bool updateShouldNotify(ShareDataWidget old) {
    return old.data != data;
  }
}

第二步,创建 InheritedWidgetTestRoute.dart 文件

class InheritedWidgetTestRoute extends StatefulWidget {
  @override
  _InheritedWidgetTestRouteState createState() => new _InheritedWidgetTestRouteState();
}

class _InheritedWidgetTestRouteState extends State<InheritedWidgetTestRoute> {
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return  Center(
      child: ShareDataWidget( // 重点:使用ShareDataWidget包裹
        data: count,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(bottom: 20.0),
              child: Text(ShareDataWidget.of(context)
              .data.toString())
            ),
            RaisedButton(
              child: Text("Increment"),
              //每点击一次,将count自增,然后更新页面渲染,ShareDataWidget的data将被更新  
              onPressed: () => setState(() => ++count),
            )
          ],
        ),
      ),
    );
  }
}
2. 对比使用:Provider

创建数据类 CounterNotifier,然后在页面中用数据类 CounterNotifier包裹child部分

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 创建 Widget 持有 CounterNotifier 数据
    return ChangeNotifierProvider.value(
      value: CounterNotifier(),
      child: MaterialApp(
        title: 'Privoder Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: ProvidePage(title: 'Provider 测试页面'),
      ),
    );
  }
}

class ProvidePage extends StatelessWidget {
  final String title;

  ProvidePage({Key key, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    // 获取 CounterNotifier 数据 (最简单的方式)
    final counter = Provider.of<CounterNotifier>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '按下按钮,使数字增长:',
            ),
            Text(
              '${counter.count}',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counter.increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}


//  核心:继承自ChangeNotifier
// 这种文件本来应该单独放在一个类文件连的
class CounterNotifier with ChangeNotifier {
  int _count = 0;
  int get count => _count;

  increment() {
    _count++;
    // 核心方法,通知刷新UI,调用build方法
    notifyListeners();
  }
}

get_it注册工具的几种方式

接下来介绍一下在get_it中注册工具都有哪几种方式

GetIt locator = GetIt.instance;

Future<void> setupLocator({bool test = false}) async {
	// 方式一,使用 registerSingleton
	// 在main.dart中调用setupLocator()时,就会立即注册ModelA
	// 注册单例,保证每一次调用ModelA工具时,都是同一个,不会重新实例化(不会造一个新工具)
	locator.registerSingleton<ModelA>(ModelA());

	// 常用.方式二,使用 registerLazySingleton
	// 调用setupLocator()时,没有生成,直到在其他地方第一次调用ServiceB工具时,才会注册
	// registerSingleton注册单例,保证每一次调用ServiceB工具时,都是同一个,不会重新实例化(不会造一个新工具)
	locator.registerLazySingleton<ServiceB>(ServiceB());
	
	// 方式三,使用 registerFactory / registerFactoryParam / registerFactoryParamAsync
	// 调用setupLocator()时,没有生成,直到在其他地方第一次调用ViewModelC工具时,才会注册
	// 参数必须时工厂函数,工厂函数不需要参数用registerFactory
	// 参数必须时工厂函数,工厂函数需要参数用registerFactoryParam
	// 参数必须时工厂函数,工厂函数是异步且需要参数用registerFactoryParamAsync
	locator.registerFactory<ViewModelC>( () => ViewModelCImpl()) );
	
	locator.registerFactoryParam<ViewModelD,String,int>((str,num) 
  	=> ViewModelDImpl(param1:str, param2: num));
  	
  	locator.registerFactoryParamAsync<ViewModelE,String,int>((str,num) 
  	=> ViewModelEImpl(param1:str, param2: num));

}

get_it提供的其他方法

  • allReady():所有在 GetIt 中注册的对象都已发出可以使用的信号时,该函数便会完成。
Future allReady(Timeout timeout)

用法示例:getIt内的工具还未准备好,那么会显示一个正在加载的 CircularProgressIndicator,如果都已经准备好了,那么会显示一个Text:

return FutureBuilder(
    future: getIt.allReady(),
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      if (snapshot.hasData) {
          return Scaffold(
            body: Center(
                child: Text('page is ok'),
            ),
          );
      } else {
      return CircularProgressIndicator();
   }
});

前端中的服务定位是什么样子

在前端中,require 其实就是服务定位。与上文中的 registerLazySingleton 方法类似,将一个又一个得工具给装入工具箱 (demo.js文件就是工具箱)

demo.js

var fs = require("fs");
var path = require("path");
var moduleA = require("./modules/moduleA");
var moduleB = require("./modules/moduleB");
参考资料

get_it 文档
GuruMeditation博客
Splat借鉴

包含get_it标准使用方法的MVVM架构模板

--------------如果文章对你有用,请右上角点赞,收藏,谢谢-------------

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值