开启成长之旅!这是我参与「日新方案 2 月更文应战」的第 7 天,点击检查活动概况

回顾原生开发

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) {
 *             @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环境怎样建立的能够看/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<String>这样的。

import 'package:get/get.dart';
class MainController extends GetxController {
  var count = 0.obs;
  plus() => count++;
}

你没有看错,直接在特点值的当地加一个.obs就能够了。这样count的值一旦被修正,就会通知刷新Obx括起来的界面。

作用演示

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