Flutter数据交互插件flutter_ddi的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter DDI Library

pub package Last Commits Issues Pull Requests Code size License

The flutter_ddi library is a Flutter package that integrates with the dart_ddi dependency injection manager, simplifying the dependency injection process in Flutter applications. It enhances code organization, flexibility, and maintainability, making the codebase more structured and scalable.

Features

The flutter_ddi offers a range of features that can be easily integrated into your Flutter application. You can choose to use or not the route management provided by the package. If preferred, you can integrate flutter_ddi solely for dependency injection, maintaining your own route logic.

  • Integration during navigation: While navigating between screens, you can utilize flutter_ddi without the need to create routes. The package simplifies passing dependencies to new screens.
  • Enhanced route building: By using flutter_ddi to construct your routes, you improve code organization by separating navigation logic from object creation logic.
  • Improved code organization: By separating navigation and dependency structures from screen and business logics, your code becomes more organized and easier to maintain, especially in large and complex projects.
  • Flexibility and scalability: This package is designed to be flexible and scalable, allowing you to add and change dependencies as needed without impact on other parts of the code.

Using flutter_ddi

Defining Modules and Routes

FlutterDDIModule

The FlutterDDIModule class is an abstraction that allows defining a module to organize and encapsulate specific dependencies.

Example Usage:

class HomeModule extends FlutterDDIModule {

  [@override](/user/override)
  FutureOr<void> onPostConstruct() {
    registerApplication<HomeRepository>(HomeRepositoryImpl.new);
    registerApplication<HomeService>(() => HomeServiceImpl(homeRepository: ddi()));
    registerApplication<HomeController>(() => HomeControllerHomeServiceImpl(homeService: ddi<HomeService>()));
  }

  [@override](/user/override)
  WidgetBuilder get page => (_) => const HomePage();

  [@override](/user/override)
  String get path => '/home';
}

FlutterDDIModuleRouter

The FlutterDDIModuleRouter class is used to define routes that contain modules. With it, you can organize the application navigation in a modular way, facilitating code maintenance and expansion.

Example Usage:

class SplashModule extends FlutterDDIModuleRouter {

  [@override](/user/override)
  WidgetBuilder get page => (_) => const SplashPage();

  [@override](/user/override)
  String get path => '/';

  [@override](/user/override)
  List<FlutterDDIModuleDefine> get modules => [
    FlutterDDIPage.from(path: '/signup', page: (_) => const SignupPage()),
    LoginModule(),
    HomeModule(),
  ];
}

You can also use the DDIModule mixin in a class that extends FlutterDDIModuleRouter. This allows creating a structure of modules with submodules.

Example Usage:

class SplashModule extends FlutterDDIModuleRouter with DDIModule {

  [@override](/user/override)
  FutureOr<void> onPostConstruct() {
    registerSingleton<DioForNative>(() => RestClient('http://my-url'));
  }

  [@override](/user/override)
  WidgetBuilder get page => (_) => const SplashPage();

  [@override](/user/override)
  String get path => '/';

  [@override](/user/override)
  List<FlutterDDIModuleDefine> get modules => [
    FlutterDDIPage.from(path: 'signup', page: (_) => const SignupPage()),
    LoginModule(),
    HomeModule(),
  ];
}

FlutterDDIFutureModuleRouter

The FlutterDDIFutureModuleRouter class is used to create modules that have Future loading. Making it possible to await for initialization before accessing the route.

Example Usage:

class SplashModule extends FlutterDDIFutureModuleRouter {

  [@override](/user/override)
  Future<void> onPostConstruct() async{
    await registerSingleton<Databaseconnection>(() async => Databaseconnection());
  }

  [@override](/user/override)
  WidgetBuilder get page => (_) => const SplashPage();

  [@override](/user/override)
  String get path => '/';

  [@override](/user/override)
  List<FlutterDDIModuleDefine> get modules => [
    FlutterDDIPage.from(path: 'signup', page: (_) => const SignupPage()),
    LoginModule(),
    HomeModule(),
  ];

  [@override](/user/override)
  Widget get error => const SizedBox.shrink();

  [@override](/user/override)
  Widget get loading => const Center(child: CircularProgressIndicator());
}

FlutterDDIPage

The FlutterDDIPage class allows defining pages that do not have any dependencies.

Example Usage:

class HomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Page'),
      ),
      body: Center(
        child: Text('Home Page Content'),
      ),
    );
  }
}

class HomeModule extends FlutterDDIPage {
  [@override](/user/override)
  WidgetBuilder get page => (_) => const HomePage();

  [@override](/user/override)
  String get path => '/home';
}

Using the FlutterDDIRouter

The FlutterDDIRouter class is a utility that allows building application routes from the defined modules and pages. With it, you can get a map of routes ready to be used with the Flutter Navigator.

Example Usage:

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      initialRoute: '/',
      routes: FlutterDDIRouter.getRoutes(
        modules: [
            SplashModule(),
        ],
      ),
    );
  }
}

Simplified State Management

Managing state in Flutter applications, especially for medium or smaller projects, doesn’t always require complex state management solutions. For apps where simplicity and efficiency are key, using these mixins and classes for state management can be a straightforward and effective approach. But for larger and complex projects, it’s recommended to use a proper state management solution.

How It Works

Under the hood, these mixins utilize the setState method to update the widget’s state. They handle registering an event or stream in the initState and cleaning up in the dispose method.

Example Usage:

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

/// You can extend `StreamListenerState` or `EventListenerState` or use the mixin `StreamListener` or `EventListener`
class _HomePageState extends StreamListenerState<HomePage, HomePageModel> {
  // class _HomePageState extends EventListenerState<HomePage, HomePageModel> {
  // class _HomePageState extends State<HomePage> with StreamListener<HomePage, HomePageModel> {
  // class _HomePageState extends State<HomePage> with EventListener<HomePage, HomePageModel> {

  Widget build(BuildContext context) {
    return Text('Welcome ${state.name} ${state.surname}');
  } 
}

class HomePageModel {
  final String name;
  final String surname;

  HomePageModel(this.name, this.surname);
}

class HomePageControler with DDIEventSender<HomePageModel> {
  // class HomePageControler with DDIStreamSender<HomePageModel>{

  String name = 'John'; 
  String surname = 'Wick';

  void update() {
    fire(HomePageModel(name, surname));
  }
}

FlutterDDIBuilder

The Widget FlutterDDIBuilder handles dependency injection by wrapping a builder and registering its module asynchronously.

Example Usage:

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Column(
      children: [
        FlutterDDIBuilder<AsyncWidgetModule>(
          module: AsyncWidgetModule.new,
          child: (context) => const MyWidget(),
          moduleName: 'AsyncWidgetModule',
          loading: const CircularProgressIndicator(),
          error: const ErrorWidget(),
        ),
      ],
    );
  } 
}

Extension FlutterDDIContext

The FlutterDDIContext extension provides a get and arguments method on the BuildContext class. The get method allows getting a dependency from the context. The arguments method allows getting the arguments passed in the route.

Example Usage:

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    final HomePageController controller = context.get<HomePageController>();

    final RouteArguments routeData = context.arguments<RouteArguments>();

    return Container();
  }
}

Known Limitation

  • Circular Routes: At present, the package does not fully support circular route structures. Defining circular dependencies between routes will lead to errors during the module registration process.

Any help, suggestions, corrections are welcome.

Example Code

Here is a complete example demonstrating the usage of flutter_ddi in a Flutter application:

import 'dart:async';

import 'package:example/model/detail.dart';
import 'package:example/page/details_screen.dart';
import 'package:example/page/first_screen.dart';
import 'package:example/page/home_screen.dart';
import 'package:example/page/second_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ddi/flutter_ddi.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter DDI Routing Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
        ),
      ),

      /// Generated Routes will be:
      ///
      /// {
      ///   '/': (_) => HomeScreen(),
      ///   '/first': (_) => FirstScreen(),
      ///   '/first/details': (_) => DetailsScreen(),
      ///   '/second': (_) => SecondScreen(),
      /// }
      routes: FlutterDDIRouter.getRoutes(
        modules: [
          AppModule(),
        ],
      ),
    );
  }
}

// Main Application Module
class AppModule extends FlutterDDIModuleRouter {
  [@override](/user/override)
  String get path => '/';

  [@override](/user/override)
  WidgetBuilder get page => (_) => const HomeScreen();

  [@override](/user/override)
  List<FlutterDDIModuleDefine> get modules => [
        FirstSubModule(),
        SecondSubModule(),
      ];
}

// First Submodule
class FirstSubModule extends FlutterDDIModuleRouter {
  [@override](/user/override)
  String get path => '/first';

  [@override](/user/override)
  WidgetBuilder get page => (_) => const FirstScreen();

  [@override](/user/override)
  List<FlutterDDIModuleDefine> get modules => [
        DetailsModule(),
      ];
}

// Details Module
class DetailsModule extends FlutterDDIModule {
  [@override](/user/override)
  String get path => '/details';

  [@override](/user/override)
  WidgetBuilder get page => (_) => DetailsScreen();

  [@override](/user/override)
  void onPostConstruct() {
    registerSingleton(() => Detail(message: 'Details Module Loaded'));
  }
}

// Second Submodule
class SecondSubModule extends FlutterDDIModule {
  [@override](/user/override)
  String get path => '/second';

  [@override](/user/override)
  WidgetBuilder get page => (_) => const SecondScreen();

  [@override](/user/override)
  FutureOr<void> onPostConstruct() {
    registerObject('Second Sub Module Loaded', qualifier: 'second_sub');
  }
}

更多关于Flutter数据交互插件flutter_ddi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据交互插件flutter_ddi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,flutter_ddi 是一个用于 Flutter 应用中数据交互的插件。尽管我无法直接提供该插件的官方实现代码(因为它可能是一个第三方库,并且我没有该库的源代码),但我可以向你展示如何使用一个假设的类似插件进行数据交互的示例。

通常,数据交互插件会提供一些基本功能,比如发送和接收数据。以下是一个假设的 flutter_ddi 使用示例,假设它提供了 sendDatareceiveData 方法。

首先,你需要在你的 pubspec.yaml 文件中添加依赖项(这里我们假设 flutter_ddi 已经存在,但在实际情况下,你需要查找并添加正确的依赖项):

dependencies:
  flutter:
    sdk: flutter
  flutter_ddi: ^x.y.z  # 替换为实际的版本号

然后,运行 flutter pub get 来获取依赖项。

接下来,在你的 Flutter 应用中使用这个插件。以下是一个简单的示例,展示如何在 Flutter 中使用 flutter_ddi 进行数据交互:

import 'package:flutter/material.dart';
import 'package:flutter_ddi/flutter_ddi.dart';  // 假设这是插件的导入路径

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

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String receivedData = "";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter DDI Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              decoration: InputDecoration(labelText: 'Enter Data'),
              onChanged: (value) {
                // 可以在这里处理文本输入变化
              },
            ),
            SizedBox(height: 16.0),
            ElevatedButton(
              onPressed: () {
                // 假设 sendData 方法接受一个字符串作为参数
                FlutterDdi.sendData("Hello, this is a test message!");
              },
              child: Text('Send Data'),
            ),
            SizedBox(height: 16.0),
            Text(
              'Received Data: $receivedData',
              style: TextStyle(fontSize: 18.0),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void initState() {
    super.initState();

    // 假设 receiveData 是一个流,我们可以监听它来获取接收到的数据
    FlutterDdi.receiveData.listen((data) {
      setState(() {
        receivedData = data;
      });
    });
  }
}

在这个示例中,我们做了以下几件事:

  1. 导入 flutter_ddi 插件。
  2. 创建一个简单的 Flutter 应用,其中包含一个文本输入框、一个发送数据的按钮和一个显示接收到的数据的文本区域。
  3. 使用 FlutterDdi.sendData 方法发送数据。
  4. 使用 FlutterDdi.receiveData 流监听接收到的数据,并在接收到新数据时更新 UI。

请注意,这只是一个假设的示例,实际的 flutter_ddi 插件可能有不同的 API 和使用方法。你应该查阅该插件的官方文档或源代码以了解正确的使用方法。如果 flutter_ddi 是一个不存在的插件名称,你可能需要找到一个实际的 Flutter 数据交互插件并按照其文档进行操作。

回到顶部