GetX项目级实战,“金三银四”春招指南

  page: () => MonthlyPage(),

  binding: MonthlyBinding(),

),

GetPage(

  name: Routes.PROFILE,

  page: () => ProfilePage(),

),

];

}




习惯了使用命名路由,所以定义了路由表。binding是 GetX 中我特别喜欢的功能——依赖注入,就像原生的 Hilt 一样,让代码结构无侵分层。并且如果使用的是流或计时器,它们将自动关闭,开发者根据不用担心。Binding 类是一个解耦依赖注入的类,在路由的时候使用。就可以知道注入的作用域,以及知道在何处以及如何处置注入的对象。



登录

--



api 是玩安卓的开放 api,登录要使用 api 和 repository,所以依赖注入的形式注入:



class LoginPageBinding implements Bindings {

@override

void dependencies() {

Get.lazyPut(() => LoginApi());

Get.lazyPut(() => LoginRepository());

Get.lazyPut(

  () => LoginController(),

);

}

}




在使用的时候直接 find:



final LoginRepository repository = Get.find();




Get.put()是最常见的注入依赖的方法,它是直接注入到内存里。你可以在任何地方找到注入的对象,这是 Provider 所没有的功能。



仅有put还不够,GetX 还提供另外一个方法,Get.lazyPut可以懒加载一个依赖,这样它只有在使用时才会被实例化。这对于计算代价高的类来说非常有用,或者如果你想在一个地方实例化几个类(比如在 Bindings 类中),但是不知道会不会使用到,那懒加载是正确的选择,是不是很像 kotlin 的 lazy。



显示密码的功能暂时未加。



![](https://img-blog.csdnimg.cn/img_convert/b0e55eda9884e9e36c0cc9c863581295.png)



在欢迎页会注入全局的依赖,然后判断是否登录,对应不同的导航:



@override

void onReady() async {

super.onReady();

await GloabConfig.init();

await DenpendencyInjection.init();

LoginProvider loginProvider = Get.find();

print(loginProvider);

// 如果未登录就登录

// 如果已登录就去task页面

if (loginProvider.isLogin()) {

  Get.offNamed(Routes.TASK);

} else {

  Get.offNamed(Routes.LOGIN);

}

}

}




Task 列表

-------



![](https://img-blog.csdnimg.cn/img_convert/8bd30929814aa81b7c9441d57e09c582.png)



主页实现了底部导航和嵌入式FloatingActionButtonLocation,没有任务的时候会弹出使用引导。点击加号可以添加任务。因为 api 是分页的,所以也做了分页处理。



@override

Widget build(BuildContext context) {

return Scaffold(

  appBar: AppBar(title: Text('My Task')),

  body: Body(),

  floatingActionButton: FloatingActionButton(

    onPressed: () {

      Get.toNamed(Routes.TASK_ADD);

    },

    child: Icon(Icons.add),

  ),

  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

  bottomNavigationBar: BottomAppBar(

    shape: CircularNotchedRectangle(),

    child: Row(

      mainAxisAlignment: MainAxisAlignment.spaceBetween,

      children: [

        IconButton(

          icon: Icon(Icons.calendar_today_sharp),

          onPressed: () {

            Get.toNamed(Routes.TASK_MOTHLY);

          },

        ),

        IconButton(

          icon: Icon(Icons.settings),

          onPressed: () {

            Get.toNamed(Routes.PROFILE);

          },

        ),

      ],

    ),

  ),

);

}

}




任务 item可以点击进入详情和侧滑,有两个侧滑菜单,编辑和删除,对应不同的功能,圆形的checkbox可以完成任务,任务标题和时间在完成时会有删除线。



GetView 就是封装的StatelessWidget,内部有一个 get方法便捷的获取注入的controller,这样连获取的步骤都能省略。



增加和编辑

-----



![](https://img-blog.csdnimg.cn/img_convert/9d20eb3ed63165836f241de8e59713ab.png)



![](https://img-blog.csdnimg.cn/img_convert/9962db40820802a3ae0fdf2bdf59d95b.png)



对应的标题是必须项,描述可以为空,时间是默认当前,优先级有高低中三个,默认是中。



选择日期会弹出日历你,采用局部刷新,提高性能,update(\[updateDateId\])函数的参数是一个 id,只会刷新对应 id 的 GetBuilder,并且 GetX 不受 InheritedWidget的限制,所以可以在任意地方引用未被内存回收的 Controller,所以可以在编辑页面,让列表页也同时刷新。



![](https://img-blog.csdnimg.cn/img_convert/1b67ea2586a93b2c3f85919293b76f97.png)



void handleDatePicker() async {

final datePick = await showDatePicker(

    context: Get.context,

    firstDate: DateTime(2000),

    initialDate: _dateTime,

    lastDate: DateTime(2100));

if (datePick != null && datePick != _dateTime) {

  _dateTime = datePick;

  task.dateStr = _dateTime.format();

  dateTimeController.text = task.dateStr;

  update([updateDateId]);

}

}

void submit() async {

if (formKey.currentState.validate()) {

  formKey.currentState.save();

  try {

    Get.loading();

    await _taskRepository.updateTask(task);

    Get.dismiss();

    // 刷新列表页

    Get.find().update();

    // controller.updateTask(task);

    Get.back();

  } catch (e) {

    print(e);

    Get.dismiss();

    Get.snackbar('Error', e.toString());

  }

}

}




月份视图

----



![](https://img-blog.csdnimg.cn/img_convert/72c1e50e9d36f17dc2f7f6600be8b81e.png)



月份视图用了table\_calendar包,这个包功能强大,可以定制日历视图。默认显示两周,点击月份展开四周的月份视图。可以按日期筛选出任务。这里的任务可以点击进入详情和点击checkbox更改状态。



TableCalendar(

      onDaySelected: (DateTime day, _, __) {

        controller.selectedDate(day);

      },

      calendarController: controller.calendarController,

      startingDayOfWeek: StartingDayOfWeek.monday,

      initialCalendarFormat: CalendarFormat.week,

      calendarStyle: CalendarStyle(

        selectedColor: Theme.of(context).accentColor,

      ),

    )



这里更改状态后,同样可以拿到列表页的Controller去更新列表页:



modifyTaskStatus(Task task) async {

try {

  TaskController taskController = Get.find();

  await taskController.modifyTaskStatus(task);

} catch (e) {}

update();

}




个人中心

----



![](https://img-blog.csdnimg.cn/img_convert/454737c05ca018ed7a2c796438f33822.png)



个人中心是一个静态页面,最下面展示了我写的 GetX 的 demo 截图。点击放大的功能放在迭代里做吧。



这里藏有福利,一个漂亮的二次元萌妹子。



扩展函数

----



在 utils文件夹下写了两个扩展函数,扩展了日期格式化和基于 GetX 的全局加载框。



extension DateExtension on DateTime {

String format() {

return formatDate(this, [

  yyyy,

  '-',

  mm,

  '-',

  dd,

]);

}

}

extension GetExtension on GetInterface {

dismiss() {

if (Get.isDialogOpen) {

  Get.back();

}

}

loading() {

if (Get.isDialogOpen) {

  Get.back();

}

Get.dialog(LoadingDialog());

}

}




使用也很简单,但不要忘了要导入扩展函数类:



dateTime.format();

Get.loading();

        。。。。。。

  Get.dismiss();



GetService

----------



GetService 我的理解是类似服务,比如 SharedPreferences、Database,还有需要异步初始化的类,放在这里注入非常合适:



TaskDao init() {

TaskDatabase database = TaskDatabase();

return TaskDao(database);

}

}

class AppSpController extends GetxService {

Future init() async {

return await SharedPreferences.getInstance();

}

}




同步的就用同步方法注入:



// 数据库

Get.put(TaskDaoController().init());



异步的用异步方法注入:



// shared_preferences

await Get.putAsync(() => AppSpController().init());



数据库 moor 的使用

------------



Android 通过 room 给开发带来的便利,用过的都知道。moor 就是 Flutter 上的 room。



Moor 使用 Dart 的源代码生成器生成代码,我们可以用函数式的调用操作数据库。这也是需要 moor\_generator 依赖项以及 build\_runner 的原因。



moor 优点之一是我们可以完全使用 Dart 操作数据库,而不必写数据库语句。这也适用于定义SQL表。创建一个表示 table 的类即可。



class Tasks extends Table {

// 可空类型

IntColumn get completeDate => integer().nullable()();

TextColumn get completeDateStr => text().nullable()();

TextColumn get content => text().nullable()();

// 为空自动生成默认值

IntColumn get date =>

  integer().clientDefault(() => DateTime.now().millisecondsSinceEpoch)();

// 为空自动生成默认值

TextColumn get dateStr =>

  text().nullable().clientDefault(() => DateTime.now().format())();

// 主键

IntColumn get id => integer().nullable().autoIncrement()();

// 为空自动生成默认值

IntColumn get priority => integer().nullable().withDefault(Constant(0))();

// 为空自动生成默认值

IntColumn get status => integer().nullable().withDefault(Constant(0))();

TextColumn get title => text()();

IntColumn get type => integer().withDefault(Constant(0))();

IntColumn get userId => integer().nullable()();

}

@UseMoor(tables: [Tasks], daos: [TaskDao])

class TaskDatabase extends _$TaskDatabase {

// we tell the database where to store the data with this constructor

TaskDatabase() : super(_openConnection());

// you should bump this number whenever you change or add a table definition. Migrations

// are covered later in this readme.

@override

int get schemaVersion => 1;

}

LazyDatabase _openConnection() {

// the LazyDatabase util lets us find the right location for the file async.

return LazyDatabase(() async {

// put the database file, called db.sqlite here, into the documents folder

// for your app.

final dbFolder = await getApplicationDocumentsDirectory();

final file = File(join(dbFolder.path, 'db.sqlite'));

return VmDatabase(file);

});

最后

感觉现在好多人都在说什么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?

Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

所以,最后这里放上我耗时两个月,将自己8年Android开发的知识笔记整理成的Android开发者必知必会系统学习资料笔记,上述知识点在笔记中都有详细的解读,里面还包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

GetX项目级实战,“金三银四”春招指南_第1张图片

以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。

最后,赠与大家一句诗,共勉!

么安卓快凉了,工作越来越难找了。又是说什么程序员中年危机啥的,为啥我这年近30的老农根本没有这种感觉,反倒觉得那些贩卖焦虑的都是瞎j8扯谈。当然,职业危机意识确实是要有的,但根本没到那种草木皆兵的地步好吗?

Android凉了都是弱者的借口和说辞。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

所以,最后这里放上我耗时两个月,将自己8年Android开发的知识笔记整理成的Android开发者必知必会系统学习资料笔记,上述知识点在笔记中都有详细的解读,里面还包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

[外链图片转存中…(img-QQOxuF0b-1630929333984)]

以上全套学习笔记面试宝典,吃透一半保你可以吊打面试官,只有自己真正强大了,有核心竞争力,你才有拒绝offer的权力,所以,奋斗吧!骚年们!千里之行,始于足下。种下一颗树最好的时间是十年前,其次,就是现在。

最后,赠与大家一句诗,共勉!

不驰于空想,不骛于虚声。不忘初心,方得始终。

你可能感兴趣的:(Android,移动开发)