Flutter平台绑定插件binding的功能介绍

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

数据绑定 #

一个用于Flutter的数据绑定状态管理包。该包受.NET INotifyPropertyChanged接口的启发,并应为那些在WPF/Xamarin中使用过.NET应用程序的.NET开发人员所熟悉。

简介 #

最近我在Medium上读了一篇关于Flutter状态管理的文章:Flutter #OneYearChallenge; Scoped Model vs BloC Pattern vs States Rebuilder

这篇文章讨论了各种不同的状态管理技术,并包含了一个挑战,作者使用自己开发的状态管理包States_rebuilder解决了该挑战。

目前,Flutter团队推荐的状态管理解决方案是Provider包。因此,我尝试使用Provider包来解决文章中的挑战。我的尝试及后续未能使用Provider包解决挑战的情况可以在这里查看。

然而,这激发了我对Flutter状态管理的好奇心,所以我决定不使用现有的包,而是从零开始创建一个状态管理解决方案来解决这个挑战。由于我的背景是.NET和C#开发,我试图利用这些技术的经验。

这个包是我为了完成挑战而创建的状态管理框架。挑战的解决方案位于示例文件夹中。

开始使用 #

要使用数据绑定包是一个简单的三步过程:

步骤1 - 创建一个继承自NotifyPropertyChanged的数据模型,并在模型的属性被更改时调用propertyChanged方法。

// CounterModel类继承自NotifyPropertyChanged,并在属性变化时触发事件
class CounterModel extends NotifyPropertyChanged {
  // 定义每个属性的常量名称(可选,但建议这样做)
  static const countPropertyName = 'count';

// 私有属性,并通过getter暴露,确保不能直接修改 int _count = 0;

int get count => _count;

// 方法,用于增加计数 void incrementCount() { _count++; // 每次属性改变时,调用propertyChanged方法通知监听者 propertyChanged(propertyName: countPropertyName); } }

步骤2 - 在应用程序的根部添加一个BindingProvider小部件。

// 应用程序的根小部件
class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Counter Example',
      // 步骤2:在应用的根部添加一个BindingProvider
      // 注意:应用中只能有一个BindingProvider
      home: BindingProvider(
        // 可选:使用BindingSource使模型实例对所有子小部件可用
        // 或者,模型也可以作为小部件的属性,在构造函数中传递给其子组件
        child: BindingSource<CounterModel>(
          instance: CounterModel(),
          child: MyHomePage(),
        ),
      ),
    );
  }
}

步骤3 - 使用Binding小部件将模型实例附加到树中,并告诉它何时应该重建。

// 主页面小部件
class MyHomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Counter Home Page'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            // 步骤3:使用Binding小部件将模型实例绑定到小部件树,并告知其何时应该重建
            Binding<CounterModel>(
              source: BindingSource.of<CounterModel>(context),
              path: CounterModel.countPropertyName,
              builder: (_, model) => Text(
                '${model.count}',
                style: Theme.of(context).textTheme.display1,
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: BindingSource.of<CounterModel>(context).incrementCount,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

现在每次调用CounterModel实例上的incrementCount方法时,都会触发propertyChanged事件。该事件会向上冒泡到全局的BindingProvider,再向下传播到所有注册接收该特定事件的Binding小部件,从而导致它们重建。


更多关于Flutter平台绑定插件binding的功能介绍的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter平台绑定插件binding的功能介绍的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter平台中,插件(Plugins)是连接Flutter应用与原生平台(如iOS和Android)功能的关键桥梁。插件绑定(Binding)是指Flutter框架与原生平台代码之间的接口,它允许Flutter代码调用原生平台特定的API。这种机制使得Flutter应用能够利用原生平台丰富的功能,如相机、文件系统访问、地理位置服务等。

以下是一个关于如何在Flutter中创建和使用平台绑定插件的简单示例,重点展示如何在Flutter中定义和使用平台通道(Method Channel),这是实现平台绑定的一种常见方式。

1. 创建Flutter插件

首先,我们需要创建一个Flutter插件项目。可以使用Flutter命令行工具来生成插件模板代码:

flutter create --template=plugin my_plugin

这将生成一个包含iOS和Android原生代码模板的Flutter插件项目。

2. 定义Method Channel

在Flutter插件的Dart代码中,我们需要定义一个Method Channel来与原生平台通信。在lib/my_plugin.dart文件中:

import 'package:flutter/services.dart';

class MyPlugin {
  static const MethodChannel _channel = const MethodChannel('com.example.my_plugin');

  static Future<String?> get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

3. 实现iOS原生代码

在iOS原生代码中,我们需要实现这个Method Channel的响应。在ios/Classes/MyPlugin.m文件中:

#import "MyPlugin.h"
#import <Flutter/Flutter.h>

@implementation MyPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    FlutterMethodChannel* channel = [FlutterMethodChannel
                                      methodChannelWithName:@"com.example.my_plugin"
                                      binaryMessenger:[registrar messenger]];
    [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
      if ([@"getPlatformVersion" isEqualToString:call.method]) {
        NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];
        result(@(version));
      } else {
        result(FlutterMethodNotImplemented);
      }
    }];
}
@end

4. 实现Android原生代码

在Android原生代码中,同样需要实现Method Channel的响应。在android/src/main/kotlin/com/example/my_plugin/MyPlugin.kt文件中:

package com.example.my_plugin

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import android.os.Build
import android.os.Bundle
import androidx.annotation.NonNull

/** MyPlugin */
class MyPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity.
  private lateinit var channel : MethodChannel

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.example.my_plugin")
    channel.setMethodCallHandler(this)
  }

  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
    if (call.method == "getPlatformVersion") {
      result.success("Android ${Build.VERSION.RELEASE}")
    } else {
      result.notImplemented()
    }
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }

  override fun onAttachedToActivity(binding: ActivityPluginBinding) {
    // No-op
  }

  override fun onDetachedFromActivityForConfigChanges() {
    // No-op
  }

  override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
    // No-op
  }

  override fun onDetachedFromActivity() {
    // No-op
  }
}

5. 使用插件

最后,在Flutter应用的Dart代码中,我们可以使用这个插件:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: FutureBuilder<String?>(
            future: MyPlugin.platformVersion,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasError) {
                  return Text('Failed to get platform version: ${snapshot.error}');
                } else {
                  return Text('Platform version: ${snapshot.data!}');
                }
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何在Flutter中创建和使用一个简单的平台绑定插件,通过Method Channel实现与原生平台的通信。根据具体需求,你可以扩展这个基础示例来实现更复杂的功能。

回到顶部