美文网首页
Flutter Provider状态管理---MVVM架构实战

Flutter Provider状态管理---MVVM架构实战

作者: Jimi | 来源:发表于2021-10-13 20:47 被阅读0次

    文章系列

    Flutter Provider状态管理---介绍、类图分析、基本使用

    Flutter Provider状态管理---八种提供者使用分析

    Flutter Provider状态管理---四种消费者使用分析

    Flutter Provider状态管理---MVVM架构实战

    视频系列

    Flutter Provider状态管理---介绍、类图分析、基本使用

    Flutter Provider状态管理---八种提供者使用分析

    Flutter Provider状态管理---四种消费者使用分析

    Flutter Provider状态管理---MVVM架构实战

    源码仓库地址

    github仓库地址

    MVVM介绍

    MVVM架构分为M(Model)、V(View)、VM(ViewModel)三个部分,他们分别处理自己的分工,在ViewModel之间使用ViewModel作为中介者,使ViewModel不受业务逻辑影响。

    Model: 模型层,处理Api数据、模型相关业务

    View: 视图层,UI呈现、使用者互动等。

    ViewModel: 视图模型,处理逻辑、将数据绑定给View展示。

    MVVM运行原理

    当界面需要展示数据时,ViewViewModel绑定,ViewModelModel取得数据后,在ViewModel处理对应的业务逻辑,然后将数据处理,最后通过View更新并展示。

    MVVM优点

    • 易于变更需求,降低耦合
    • 权责分工明确
    • 方便测试

    MVVM缺点

    • 文件数量增加
    • bug定位较为不易
    • 数据绑定消耗资源

    MVVM实战

    下面这个项目实战是用ProviderMVVM搭建的架构,是一个笑话段子列表。

    它包含了5主要类:

    • Service: 网络请求类
    • Model: 主要负责转换模型
    • View: 主要负责呈现UI,通过ViewModel获取数据并展示
    • Widgets: 单独的UI模块分离
    • ViewModel: 处理业务逻辑,将数据绑定给View展示

    定义模型

    将网络请求回来的数据转换为对应的模型

    import 'dart:convert';
    
    JokeModel jokeModelFromJson(String str) => JokeModel.fromJson(json.decode(str));
    
    String jokeModelToJson(JokeModel data) => json.encode(data.toJson());
    
    class JokeModel {
      JokeModel({
        this.data,
      });
    
      final List<Joke>? data;
    
      factory JokeModel.fromJson(Map<String, dynamic> json) => JokeModel(
        data: List<Joke>.from(json["data"].map((x) => Joke.fromJson(x))),
      );
    
      Map<String, dynamic> toJson() => {
        "data": List<dynamic>.from(data!.map((x) => x.toJson())),
      };
    }
    
    class Joke {
      Joke({
        this.content,
        this.hashId,
        this.unixtime,
        this.updatetime,
      });
    
      final String? content;
      final String? hashId;
      final int? unixtime;
      final String? updatetime;
    
      factory Joke.fromJson(Map<String, dynamic> json) => Joke(
        content: json["content"],
        hashId: json["hashId"],
        unixtime: json["unixtime"],
        updatetime: json["updatetime"],
      );
    
      Map<String, dynamic> toJson() => {
        "content": content,
        "hashId": hashId,
        "unixtime": unixtime,
        "updatetime": updatetime,
      };
    }
    

    定义网络请求类

    网络请求用到第三方网路请求库Dio ^4.0.0,将请求回来的数据转换为模型,并更新ViewModel数据。

    import 'dart:convert';
    import 'package:dio/dio.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/model/joke_model.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/view_model/joke_view_model.dart';
    
    class JokeService {
      static Future<void> getJokes(JokeViewModel jokeViewModel) async {
    
        var response = await Dio().get("http://v.juhe.cn/joke/content/text.php?page=1&pagesize=20&key=03303e4d34effe095cf6a4257474cda9");
        if (response.statusCode == 200) {
          // 转换模型
          JokeModel jokeModel = jokeModelFromJson(json.encode(response.data["result"]));
          // 更新数据
          jokeViewModel.setJokeList(jokeModel);
        }
      }
    }
    

    定义ViewModel

    这个ViewModel主要负责把请求回来的数据进行处理,并通知View层更新数据

    import 'package:flutter/material.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/model/joke_model.dart';
    
    class JokeViewModel with ChangeNotifier {
    
      List<Joke>? _jokeList = [];
    
      late Joke _joke;
    
      bool loading = true;
    
      setJokeList(JokeModel jokeModel) {
        _jokeList = [];
        _jokeList = jokeModel.data;
        loading = false;
        notifyListeners();
      }
    
      setJoke(Joke joke) {
        _joke = joke;
      }
    
      List<Joke>? get jokeList => _jokeList;
    
      Joke get joke => _joke;
    }
    

    定义View

    我们在页面刚进入时进行初始化,然后通过ProviderConsumer来进行监听状态的变化。

    import 'package:flutter/material.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/service/joke_service.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/view_model/joke_view_model.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/widgets/joke_item.dart';
    import 'package:provider/provider.dart';
    
    class JokeView extends StatefulWidget {
      @override
      _JokeViewState createState() => _JokeViewState();
    }
    
    class _JokeViewState extends State<JokeView> {
      @override
      void initState() {
    
        // 获取接口数据
        JokeService.getJokes(Provider.of<JokeViewModel>(context, listen: false));
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Provider + MVVM"),
          ),
          body: Consumer<JokeViewModel>(
            builder: (_, jokeViewModel, child) {
    
              JokeViewModel _jokeViewModel = jokeViewModel;
    
    
              if (jokeViewModel.loading) {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }
    
              return ListView.separated(
                itemBuilder: (_, index) {
                  _jokeViewModel.setJoke(_jokeViewModel.jokeList![index]);
    
                  return JokeItem(jokeViewModel: _jokeViewModel);
                },
                itemCount: _jokeViewModel.jokeList?.length ?? 0,
                separatorBuilder: (_, index) {
                  return Divider(
                    height: 1,
                  );
                },
              );
    
            },
          ),
        );
      }
    }
    

    定义Widgets

    把需要单独抽离的UI放在widgets中,并把ViewModel传入进来。

    import 'package:flutter/material.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/model/joke_model.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/view_model/joke_view_model.dart';
    
    class JokeItem extends StatelessWidget {
    
      JokeItem({
        Key? key,
        this.jokeViewModel
      }) : super(key: key);
    
      final JokeViewModel? jokeViewModel;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.only(
            left: 15,
            right: 15,
            top: 10,
            bottom: 10
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              Text("${jokeViewModel?.joke?.content ?? ""}",
                style: TextStyle(
                  color: Colors.black87,
                  letterSpacing: 1.3,
                  wordSpacing: 2
                ),
              ),
              SizedBox(height: 5,),
              Text("${jokeViewModel?.joke?.updatetime ?? "--"}")
            ],
          ),
        );
      }
    }
    

    引用View

    import 'package:flutter/material.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/view/joke_view.dart';
    
    class ProviderMvvmExample extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return JokeView();
      }
    }
    
    

    应用程序入口设置

    import 'package:flutter/material.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/provider_mvvm_example.dart';
    import 'package:flutter_provider_example/provider_mvvm_example/view_model/joke_view_model.dart';
    import 'package:provider/provider.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return ChangeNotifierProvider(
          create: (_) => JokeViewModel(),
          child: MaterialApp(
            debugShowCheckedModeBanner: false,
            home: ProviderMvvmExample(),
          ),
        );
      }
    }
    

    运行结果

    [图片上传失败...(image-63254f-1633573555937)]

    总结

    以上就是一个很简单的列表功能MVVM示例,在实际的情况下也不见得这是最好的方式,MVVM还有很多变种写法,但核心是一样的。

    最后说一句,架构只是辅助而已,世界没有最好的架构。与其讨论这些,还不如想想这些架构为什么会出现?它的前因后果又是什么?在什么情况下要使用哪种架构?

    相关文章

      网友评论

          本文标题:Flutter Provider状态管理---MVVM架构实战

          本文链接:https://www.haomeiwen.com/subject/nxnanltx.html