Flutter MVVM架构插件umvvm的使用

Flutter MVVM架构插件umvvm的使用

UMVVM库

UMVVM库是一组用于Flutter应用架构的类。

安装

pubspec.yaml 文件中添加以下依赖项:

dependencies: 
  umvvm: ^<最新版本>

dev_dependencies: 
  umvvm_generator: ^<最新版本>

如果你还没有安装 build_runner,还需要添加以下依赖项:

dev_dependencies: 
  build: ^<最新版本>
  build_config: ^<最新版本>
  build_runner: ^<最新版本>

要构建或重新生成生成的文件,请运行以下命令:

flutter pub run build_runner build --delete-conflicting-outputs

示例

最小示例可以在 这里 找到。

更复杂的示例可以在 这里 找到。这些示例包括基本组件的使用、导航示例和数据库连接示例。

文档

以下是一个小示例,演示了所有组件的使用:

import 'package:dart_mappable/dart_mappable.dart';
import 'package:dio/dio.dart' as dio;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:umvvm/umvvm.dart';

part 'main.api.dart';
part 'main.mvvm.dart';
part 'main.mapper.dart';

class PostLikedEvent {
  final int id;

  const PostLikedEvent({
    required this.id,
  });
}

[@MappableClass](/user/MappableClass)()
class Post with PostMappable {
  const Post({
    required this.title,
    required this.body,
    required this.id,
    this.isLiked = false,
  });

  final String? title;
  final String? body;
  final int? id;
  final bool isLiked;

  static const fromMap = PostMapper.fromMap;
}

[@MappableClass](/user/MappableClass)()
class PostsState with PostsStateMappable {
  const PostsState({
    this.posts,
  });

  final StatefulData<List<Post>>? posts;
}

[@mainApi](/user/mainApi)
class Apis with ApisGen {}

[@mainApp](/user/mainApp)
class App extends UMvvmApp with AppGen {
  final apis = Apis();

  [@override](/user/override)
  Future<void> initialize() async {
    await super.initialize();
  }
}

final app = App();

Future<void> main() async {
  await app.initialize();

  runApp(const MaterialApp(home: PostsListView()));
}

class HttpRequest<T> extends DioRequest<T> {
  [@override](/user/override)
  RequestSettings get defaultSettings => RequestSettings(
        logPrint: (message) {
          print(message);
        },
        exceptionPrint: (error, trace) {
          print(error);
          print(trace);
        },
      );
}

[@api](/user/api)
class PostsApi {
  HttpRequest<List<Post>> getPosts(int offset, int limit) =>
      HttpRequest<List<Post>>()
        ..method = RequestMethod.get
        ..baseUrl = 'http://jsonplaceholder.typicode.com'
        ..url = '/posts'
        ..parser = (result, headers) async {
          final list = <Post>[];

          result?.forEach((data) {
            list.add(Post.fromMap(data));
          });

          return list;
        };
}

[@basicInstance](/user/basicInstance)
class PostsInteractor extends BaseInteractor<PostsState, Map<String, dynamic>?> {
  Future<void> loadPosts(int offset, int limit, {bool refresh = false}) async {
    updateState(state.copyWith(posts: const LoadingData()));

    late Response<List<Post>> response;

    if (refresh) {
      response = await executeAndCancelOnDispose(app.apis.posts.getPosts(0, limit));
    } else {
      response = await executeAndCancelOnDispose(app.apis.posts.getPosts(offset, limit));
    }

    if (response.isSuccessful) {
      updateState(state.copyWith(posts: SuccessData(result: response.result ?? [])));
    } else {
      updateState(state.copyWith(posts: ErrorData(error: response.error)));
    }
  }

  [@override](/user/override)
  List<EventBusSubscriber> subscribe() => [
        on<PostLikedEvent>((event) {
          // 更新帖子列表...
        }),
      ];

  [@override](/user/override)
  PostsState get initialState => const PostsState();
}

class PostsListViewState {}

class PostsListViewModel extends BaseViewModel<PostsListView, PostsListViewState> {
  [@override](/user/override)
  DependentMvvmInstanceConfiguration get configuration =>
      DependentMvvmInstanceConfiguration(
        dependencies: [
          app.connectors.postsInteractorConnector(),
        ],
      );

  late final postsInteractor = getLocalInstance<PostsInteractor>();

  [@override](/user/override)
  void onLaunch() {
    postsInteractor.loadPosts(0, 30, refresh: true);
  }

  void openPost(Post post) {
    // 了解更多关于导航组件的信息...

    // app.navigation.routeTo(
    //   app.navigation.routes.post(
    //     post: post,
    //   ),
    //   forceGlobal: true,
    // );
  }

  void like(int id) {
    app.eventBus.send(PostLikedEvent(id: id));
  }

  Stream<StatefulData<List<Post>>?> get postsStream => postsInteractor.updates((state) => state.posts);

  [@override](/user/override)
  PostsListViewState get initialState => PostsListViewState();
}

class PostsListView extends BaseWidget {
  const PostsListView({
    super.key,
    super.viewModel,
  });

  [@override](/user/override)
  State<StatefulWidget> createState() {
    return _PostsListViewWidgetState();
  }
}

class _PostsListViewWidgetState extends BaseView<PostsListView, PostsListViewState, PostsListViewModel> {
  [@override](/user/override)
  Widget buildView(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color.fromARGB(255, 232, 232, 232),
      appBar: AppBar(title: const Text('Posts')),
      body: StreamBuilder<StatefulData<List<Post>>?>(
        stream: viewModel.postsStream,
        builder: (context, snapshot) {
          if (snapshot.hasData && snapshot.data != null) {
            return buildList(snapshot.data!);
          }

          return Container();
        },
      ),
    );
  }

  Widget buildList(StatefulData<List<Post>> data) {
    switch (data) {
      case LoadingData():
        return const Center(child: CircularProgressIndicator());
      case SuccessData<List<Post>>(:final result):
        return ListView.builder(
          itemBuilder: (context, index) {
            final item = result[index];

            return PostCard(
              onTap: () {
                viewModel.openPost(item);
              },
              onLikeTap: () {
                viewModel.like(item.id ?? 1);
              },
              title: item.title ?? '',
              body: item.body ?? '',
              isLiked: item.isLiked,
            );
          },
          itemCount: result.length,
        );
      case ErrorData<List<Post>>(:final error):
        return Text(error.toString());
    }
  }

  [@override](/user/override)
  PostsListViewModel createViewModel() => PostsListViewModel();
}

更多关于Flutter MVVM架构插件umvvm的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter MVVM架构插件umvvm的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于在Flutter项目中使用MVVM架构插件umvvm,以下是一个基本的代码示例,展示了如何设置和使用该插件来实现MVVM架构。假设你已经在pubspec.yaml文件中添加了umvvm依赖并运行了flutter pub get

1. 添加依赖

首先,确保你的pubspec.yaml文件中包含以下依赖:

dependencies:
  flutter:
    sdk: flutter
  umvvm: ^最新版本号  # 替换为实际最新版本号

2. 创建ViewModel

在你的项目中创建一个ViewModel类。这个类将包含业务逻辑和数据状态。

import 'package:umvvm/umvvm.dart';

class CounterViewModel extends BaseViewModel {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();  // 通知视图更新
  }
}

3. 创建View(Widget)

在你的lib目录下创建一个新的Dart文件,比如counter_view.dart,并在其中创建一个使用ViewModel的Widget。

import 'package:flutter/material.dart';
import 'package:umvvm/umvvm.dart';
import 'counter_view_model.dart';  // 假设你将ViewModel放在这个文件

class CounterView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelProvider<CounterViewModel>.withConsumer(
      viewModel: CounterViewModel(),
      builder: (context, viewModel, child) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Flutter MVVM with umvvm'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '${viewModel.count}',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              viewModel.increment();
            },
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ),
        );
      },
    );
  }
}

4. 使用View

在你的main.dart文件中使用这个CounterView

import 'package:flutter/material.dart';
import 'counter_view.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CounterView(),
    );
  }
}

总结

以上代码展示了如何在Flutter项目中使用umvvm插件来实现MVVM架构。ViewModel负责业务逻辑和数据状态管理,而View(Widget)负责展示数据并响应用户交互。ViewModelProvider用于将ViewModel注入到View中,并通过notifyListeners方法通知视图更新。

请注意,这只是一个简单的示例。在实际项目中,你可能需要根据具体需求对ViewModelView进行更复杂的实现,并可能需要处理更多的状态管理和依赖注入。

回到顶部