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

待兔
• 阅读 395

回顾原生开发

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

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

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

package androidx.databinding;

import androidx.annotation.Nullable;

import java.io.Serializable;

/**
 * An object wrapper to make it observable.
 * <p>
 * Observable field classes may be used instead of creating an Observable object. It can also
 * create a calculated field, depending on other fields:
 * <pre><code>public class MyDataObject {
 *     private Context context;
 *     public final ObservableField&lt;String&gt; first = new ObservableField&lt;String&gt;();
 *     public final ObservableField&lt;String&gt; last = new ObservableField&lt;String&gt;();
 *     public final ObservableField&lt;String&gt; display =
 *         new ObservableField&lt;String&gt;(first, last) {
 *             &#64;Override
 *             public String get() {
 *                 return context.getResources().getString(R.string.name, first.get, last.get());
 *             }
 *         };
 *     public final ObservableInt age = new ObservableInt();
 * }</code></pre>
 * Fields of this type should be declared final because bindings only detect changes in the
 * field's value, not of the field itself.
 *
 * @param <T> The type parameter for the actual object.
 * @see ObservableParcelable
 */
public class ObservableField<T> extends BaseObservableField implements Serializable {
    static final long serialVersionUID = 1L;
    private T mValue;

    /**
     * Wraps the given object and creates an observable object
     *
     * @param value The value to be wrapped as an observable.
     */
    public ObservableField(T value) {
        mValue = value;
    }

    /**
     * Creates an empty observable object
     */
    public ObservableField() {
    }

    /**
     * Creates an ObservableField that depends on {@code dependencies}. Typically,
     * ObservableFields are passed as dependencies. When any dependency
     * notifies changes, this ObservableField also notifies a change.
     *
     * @param dependencies The Observables that this ObservableField depends on.
     */
    public ObservableField(Observable... dependencies) {
        super(dependencies);
    }

    /**
     * @return the stored value.
     */
    @Nullable
    public T get() {
        return mValue;
    }

    /**
     * Set the stored value.
     *
     * @param value The new value
     */
    public void set(T value) {
        if (value != mValue) {
            mValue = value;
            notifyChange();
        }
    }
}

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

框架搭建

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

flutter pub add get

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

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

import 'package:flutter/material.dart';
import 'package:flutter_mvvm_demo/home_binding.dart';
import 'package:flutter_mvvm_demo/main_binding.dart';
import 'package:flutter_mvvm_demo/home_view.dart';
import 'package:flutter_mvvm_demo/main_view.dart';
import 'package:get/get.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialRoute: '/home',
      getPages: [
        GetPage(
          name: '/home',
          page: () => const HomeView(),
          binding: HomeBinding(),
        ),
        GetPage(
          name: '/main',
          page: () => const MainView(),
          binding: MainBinding(),
        ),
      ],
    );
  }
}

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

import 'package:flutter_mvvm_demo/home_controller.dart';
import 'package:get/get.dart';

class HomeBinding extends Bindings {

  @override
  void dependencies() {
    Get.put(HomeController());
  }
}
import 'package:flutter_mvvm_demo/main_controller.dart';
import 'package:get/get.dart';

class MainBinding extends Bindings {

  @override
  void dependencies() {
    Get.put(MainController());
  }
}

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

import 'package:flutter/material.dart';
import 'package:flutter_mvvm_demo/home_controller.dart';
import 'package:get/get.dart';

class HomeView extends GetView<HomeController> {
  const HomeView({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(onPressed: () {
        Get.toNamed('/main');
      }, child: const Text('跳转主界面')) ,
    );
  }
}
import 'package:flutter/material.dart';
import 'package:flutter_mvvm_demo/main_controller.dart';
import 'package:get/get.dart';

class MainView extends GetView<MainController> {
  const MainView({super.key});

  @override
  Widget build(BuildContext context) {
    return Obx(() => Row(children: [
      Text('${controller.count}'),
      ElevatedButton(onPressed: () {
        controller.plus();
      }, child: const Text('+'))
    ]));
  }
}

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

import 'package:get/get.dart';

class MainController extends GetxController {

  var count = 0.obs;

  plus() => count++;
}

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

效果演示

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

点赞
收藏
评论区
推荐文章
浩浩 浩浩
3年前
【Flutter 实战】移动开发技术简介
1.1移动开发技术简介本节将主要介绍一下移动开发技术的进化历程,主要是想让读者知道Flutter技术出现的背景。笔者认为,了解一门新技术出现的背景是非常重要的,因为只有了解之前是什么样的,才能理解为什么会是现在这样。1.1.1原生开发与跨平台技术原生开发原生应用程序是指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开
Souleigh ✨ Souleigh ✨
3年前
快速入门 WePY 小程序
一、WePY介绍WePY是 _腾讯_参考了Vue等框架对原生小程序进行再次封装的框架,更贴近于MVVM架构模式,并支持ES6/7的一些新特性。二、WePY使用1、WePY的安装或更新都通过npm进行:npminstallgwepyc
浩浩 浩浩
3年前
【Flutter实战】 路由管理
2.2路由管理路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter中的路由管理和原生开发类似,无论是Android还是
APICloud平台常用技术点汇总详解
APICloud移动低代码开发平台介绍:使用APICloud可以开发移动APP、小程序、html5网页应用。如果要实现编写一套代码编译为多端应用(移动APP、小程序、html5),需使用avm.js框架进行开发。如果只开发APP,则可以使用前端技术(HTML5、Vue、react等)、avm.js进行开发,还可以使用模块商店大量的原生
Stella981 Stella981
2年前
Android&Flutter混合开发初体验
最近flutter不是一般的火呀,但对于一些成熟的产品来说,完全摒弃原有App的历史沉淀,全面转向Flutter是不现实的。因此使用Flutter去统一Android、iOS技术栈,把它作为已有原生App的扩展能力,通过有序推进来提升移动端的开发效率(1)创建flutter模块,创建module后会AS会自动进行flutter的相关配置!在这里
Stella981 Stella981
2年前
Android编译出现DSL element android.dataBinding.enabled is obsolete and has been replaced with android
一、问题 编译的时候发现,发现以下警告,大概意思是 DSL元素的android.dataBinding。已被替换为“android.buildFeatures.dataBinding”,它将在5.0版的AndroidGradle插件中被删除。build.gradle:DSLelement'android.dataBi
程昱 程昱
1个月前
移动端架构师 20周完结
移动端架构师20周完结download》quangneng.com/1279/一、关于移动端架构师的了解:移动端架构师是负责设计和规划移动应用程序或移动平台整体架构的专业人员。他们在移动应用开发过程中扮演关键角色,负责确定应用程序的整体结构、技术选型、系统
韦康 韦康
3星期前
移动端架构师 20周完结
移动端架构师20周完结download》quangneng.com/1279/一、关于移动端架构师的了解:移动端架构师是负责设计和规划移动应用程序或移动平台整体架构的专业人员。他们在移动应用开发过程中扮演关键角色,负责确定应用程序的整体结构、技术选型、系统
臧霸 臧霸
2星期前
uni-app实战在线教育类app开发
uniapp是一个跨平台的开发框架,可以在多个移动端平台(如iOS、Android等)上使用一套代码进行开发。通过使用uniapp,您可以使用Vue.js编写代码,并将其打包为原生应用,以实现在线教育类app的开发。以下是使用uniapp实战开发在线教育类
陈元 陈元
1星期前
RN从0到1系统精讲与小红书APP实战(2023版)|完结无密
RN从0到1系统精讲与小红书APP实战(2023版)|完结无密download》quangneng.com/159/ReactNative(RN)是一个流行的跨平台移动应用开发框架,允许开发者使用JavaScript和React来构建原生移动应用。下面是一
待兔
待兔
Lv1
男 · helloworld公司 · CTO - helloworld开发者社区站长
helloworld开发者社区网站站长
文章
89
粉丝
44
获赞
77