Flutter开发 - 使用GetX框架实现类似MVVM架构

回顾原生开发

在Android原生开发中,通常是使用Databinding实现MVVM架构,只需要在gradle中开启databinding的选项,然后使用ObservableField或LiveData即可。

1buildFeatures { 2 dataBinding true 3} 4
1<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> 2 <data> 3 <variable name="m" type="com.example.vm.LoginViewModel" /> 4 </data> 5 <EditText android:text="@{m.username}"/> 6</layout> 7

在ViewModel中可以定义ObservableField,这样界面就可以直接观察了。简单看一下ObservableField的源码,其实还有另外的几个类也是类似的功能,比如ObservableInt和ObservableBoolean。

1package androidx.databinding; 2 3import androidx.annotation.Nullable; 4 5import java.io.Serializable; 6 7/** 8 * An object wrapper to make it observable. 9 * <p> 10 * Observable field classes may be used instead of creating an Observable object. It can also 11 * create a calculated field, depending on other fields: 12 * <pre><code>public class MyDataObject { 13 * private Context context; 14 * public final ObservableField&lt;String&gt; first = new ObservableField&lt;String&gt;(); 15 * public final ObservableField&lt;String&gt; last = new ObservableField&lt;String&gt;(); 16 * public final ObservableField&lt;String&gt; display = 17 * new ObservableField&lt;String&gt;(first, last) { 18 * &#64;Override 19 * public String get() { 20 * return context.getResources().getString(R.string.name, first.get, last.get()); 21 * } 22 * }; 23 * public final ObservableInt age = new ObservableInt(); 24 * }</code></pre> 25 * Fields of this type should be declared final because bindings only detect changes in the 26 * field's value, not of the field itself. 27 * 28 * @param <T> The type parameter for the actual object. 29 * @see ObservableParcelable 30 */ 31public class ObservableField<T> extends BaseObservableField implements Serializable { 32 static final long serialVersionUID = 1L; 33 private T mValue; 34 35 /** 36 * Wraps the given object and creates an observable object 37 * 38 * @param value The value to be wrapped as an observable. 39 */ 40 public ObservableField(T value) { 41 mValue = value; 42 } 43 44 /** 45 * Creates an empty observable object 46 */ 47 public ObservableField() { 48 } 49 50 /** 51 * Creates an ObservableField that depends on {@code dependencies}. Typically, 52 * ObservableFields are passed as dependencies. When any dependency 53 * notifies changes, this ObservableField also notifies a change. 54 * 55 * @param dependencies The Observables that this ObservableField depends on. 56 */ 57 public ObservableField(Observable... dependencies) { 58 super(dependencies); 59 } 60 61 /** 62 * @return the stored value. 63 */ 64 @Nullable 65 public T get() { 66 return mValue; 67 } 68 69 /** 70 * Set the stored value. 71 * 72 * @param value The new value 73 */ 74 public void set(T value) { 75 if (value != mValue) { 76 mValue = value; 77 notifyChange(); 78 } 79 } 80} 81

databinding里面的ObservableField类可以帮助我们很好的实现数据的双向绑定,通过调用它 的get()方法就可以拿到值了,在xml中也可以很方便地使用其值。 这样一种优雅的写法,在Flutter中怎么玩呢?还是那句话,巧妇难为无米之炊,首先你得有Flutter的开发环境,要不然你也就只能看看了。如果不了解Flutter环境怎么搭建的可以看juejin.cn/post/718557… 这篇文章。那么我们开向幼儿园的车马上就要发车了。不好意思,说错了,是开往大前端大佬的车。

框架搭建

我们先大概了解下Flutter项目的项目结构,由于这是一个演示Demo,我这里就不分包了,你们可以写的更优雅。集成get框架就一个命令,flutter就是这么简单。

flutter pub add get

项目结构

内行人一眼就看出我们肯定是先看main.dart文件。

1import 'package:flutter/material.dart'; 2import 'package:flutter_mvvm_demo/home_binding.dart'; 3import 'package:flutter_mvvm_demo/main_binding.dart'; 4import 'package:flutter_mvvm_demo/home_view.dart'; 5import 'package:flutter_mvvm_demo/main_view.dart'; 6import 'package:get/get.dart'; 7 8void main() { 9 runApp(const MyApp()); 10} 11 12class MyApp extends StatelessWidget { 13 const MyApp({super.key}); 14 15 @override 16 Widget build(BuildContext context) { 17 return GetMaterialApp( 18 initialRoute: '/home', 19 getPages: [ 20 GetPage( 21 name: '/home', 22 page: () => const HomeView(), 23 binding: HomeBinding(), 24 ), 25 GetPage( 26 name: '/main', 27 page: () => const MainView(), 28 binding: MainBinding(), 29 ), 30 ], 31 ); 32 } 33} 34

这个MyApp就是我们程序的入口,相当于Application类,其实最主要是因为在main()方法中调了一个runApp()方法,然后传入了我们的第一个视图。在Flutter中,不是管View叫视图。Flutter中的视图有两种,一种是有状态的StatefulWidget,还有一种是无状态的StatelessWidget。我们这里返回了一个GetMaterialApp,里面指定了两个属性。initialRoute代表第一个页面的路由,getPages中指定所有的页面。GetPage里面的page指定了这个页面的视图Widget,然后使用binding指定依赖注入,简单说就是不用在使用的时候new对象,直接注入到属性中。

1import 'package:flutter_mvvm_demo/home_controller.dart'; 2import 'package:get/get.dart'; 3 4class HomeBinding extends Bindings { 5 6 @override 7 void dependencies() { 8 Get.put(HomeController()); 9 } 10} 11
1import 'package:flutter_mvvm_demo/main_controller.dart'; 2import 'package:get/get.dart'; 3 4class MainBinding extends Bindings { 5 6 @override 7 void dependencies() { 8 Get.put(MainController()); 9 } 10} 11

调用Get.put()方法我们就注入了controller,之后我们可以直接在视图层拿到这个controller。

1import 'package:flutter/material.dart'; 2import 'package:flutter_mvvm_demo/home_controller.dart'; 3import 'package:get/get.dart'; 4 5class HomeView extends GetView<HomeController> { 6 const HomeView({super.key}); 7 8 @override 9 Widget build(BuildContext context) { 10 return Center( 11 child: ElevatedButton(onPressed: () { 12 Get.toNamed('/main'); 13 }, child: const Text('跳转主界面')) , 14 ); 15 } 16} 17
1import 'package:flutter/material.dart'; 2import 'package:flutter_mvvm_demo/main_controller.dart'; 3import 'package:get/get.dart'; 4 5class MainView extends GetView<MainController> { 6 const MainView({super.key}); 7 8 @override 9 Widget build(BuildContext context) { 10 return Obx(() => Row(children: [ 11 Text('${controller.count}'), 12 ElevatedButton(onPressed: () { 13 controller.plus(); 14 }, child: const Text('+')) 15 ])); 16 } 17} 18

视图层我们直接继承GetView比较方便,这样可以直接拿到之前注入的controller。使用Obx括起来的内容,当被观察的属性值被修改时,直接更新Obx里面的界面。我们再来看一看怎么定义可以被观察的属性,类似于原生开发中ObservableField<String>这样的。

1import 'package:get/get.dart'; 2 3class MainController extends GetxController { 4 5 var count = 0.obs; 6 7 plus() => count++; 8} 9

你没有看错,直接在属性值的地方加一个.obs就可以了。这样count的值一旦被修改,就会通知刷新Obx括起来的界面。

效果演示

mvvmdemo.gif

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

APICloud平台常用技术点汇总详解

APICloud移动低代码开发平台介绍:使用APICloud可以开发移动APP、小程序、html5网页应用。如果要实现编写一套代码编译为多端应用(移动APP、小程序、html5),需使用avm.js框架进行开发。如果只开发APP,则可以使用前端技术(HTML5、Vue、react等)、avm.js进行开发,还可以使用模块商店大量的原生

【Flutter 实战】移动开发技术简介

1.1移动开发技术简介本节将主要介绍一下移动开发技术的进化历程,主要是想让读者知道Flutter技术出现的背景。笔者认为,了解一门新技术出现的背景是非常重要的,因为只有了解之前是什么样的,才能理解为什么会是现在这样。1.1.1原生开发与跨平台技术原生开发原生应用程序是指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开

快速入门 WePY 小程序

一、WePY介绍WePY是 _腾讯_参考了Vue等框架对原生小程序进行再次封装的框架,更贴近于MVVM架构模式,并支持ES6/7的一些新特性。二、WePY使用1、WePY的安装或更新都通过npm进行:npminstallgwepyc

【Flutter实战】 路由管理

2.2路由管理路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter中的路由管理和原生开发类似,无论是Android还是

Android&Flutter混合开发初体验

最近flutter不是一般的火呀,但对于一些成熟的产品来说,完全摒弃原有App的历史沉淀,全面转向Flutter是不现实的。因此使用Flutter去统一Android、iOS技术栈,把它作为已有原生App的扩展能力,通过有序推进来提升移动端的开发效率(1)创建flutter模块,创建module后会AS会自动进行flutter的相关配置!在这里