当前位置: 首页 > web >正文

打通 Flutter 与原生状态管理:Android ViewModel 的运用

在 FlutterActivity 中使用 ViewModel 是一个结合了 Flutter 和 Android 原生开发(Android Jetpack)的常见场景。这通常用于需要在 Flutter 和原生 Android 代码之间共享状态或逻辑的情况。

核心思路是:

  1. 在 Android 原生端(即在 FlutterActivity 或其附属的 Fragment/Activity 中)创建和管理一个 Android ViewModel。
  2. 通过 MethodChannel 在 Flutter 和原生端之间建立通信桥梁。
  3. Flutter 端通过 MethodChannel 发送指令或请求数据。
  4. 原生端的 ViewModel 处理业务逻辑,并可以通过多种方式(如 LiveData、Flow、回调等)将数据返回给 Flutter。

下面我们通过一个详细的示例来实现这个过程。我们将创建一个简单的计数器,其数据源是 Android 端的 ViewModel。


步骤 1:在 Android 原生端设置

首先,确保你的 android/app/build.gradle 文件中添加了 AndroidX 和 Lifecycle 依赖(对于新项目,这些通常已默认包含)。

dependencies {def lifecycle_version = "2.6.2" // 使用最新稳定版implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"// ... 其他依赖
}
  1. 创建 Android ViewModel

在 android/app/src/main/kotlin/…/ 你的包名下,创建一个 ViewModel 类。

CounterViewModel.kt

package com.yourcompany.yourapp // 替换为你的包名import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModelclass CounterViewModel : ViewModel() {// 使用 LiveData 来持有计数器的状态,以便 Flutter 端观察private val _counter = MutableLiveData<Int>(0)val counter: LiveData<Int> = _counterfun increment() {_counter.value = (_counter.value ?: 0) + 1}fun decrement() {_counter.value = (_counter.value ?: 0) - 1}fun getCurrentCount(): Int {return _counter.value ?: 0}
}
  1. 在 FlutterActivity 中集成 ViewModel 和 MethodChannel

接下来,你需要创建一个自定义的 FlutterActivity 来托管 ViewModel 并处理来自 Flutter 的调用。

MainActivity.kt

package com.yourcompany.yourapp // 替换为你的包名import androidx.lifecycle.ViewModelProvider
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannelclass MainActivity : FlutterActivity() {// 定义 MethodChannel 的名称,确保与 Flutter 端一致private val CHANNEL = "samples.flutter.dev/native_counter"// 延迟初始化 ViewModelprivate lateinit var counterViewModel: CounterViewModeloverride fun configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)// 初始化 ViewModelcounterViewModel = ViewModelProvider(this).get(CounterViewModel::class.java)// 设置 MethodChannelMethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->// 处理来自 Flutter 的方法调用when (call.method) {"increment" -> {counterViewModel.increment()result.success(null) // 通知 Flutter 调用成功}"decrement" -> {counterViewModel.decrement()result.success(null)}"getCurrentCount" -> {val currentCount = counterViewModel.getCurrentCount()result.success(currentCount) // 将当前计数返回给 Flutter}else -> {result.notImplemented()}}}// (可选) 如果你想主动从原生端推送数据到 Flutter(例如使用 EventChannel 监听 LiveData)// 这部分更复杂,通常用 MethodChannel 的 “调用-返回” 模式就够了。}
}

重要: 确保你的 AndroidManifest.xml 使用的是这个自定义的 MainActivity。 android/app/src/main/AndroidManifest.xml

<activityandroid:name=".MainActivity" <!-- 确保是这个 -->android:exported="true"android:launchMode="singleTop"... >...
</activity>

步骤 2:在 Flutter 端设置

现在,在 Flutter 代码中,你需要创建一个对应的 MethodChannel 来与原生端通信。

  1. 创建 MethodChannel 工具类

native_counter_service.dart

import 'package:flutter/services.dart';class NativeCounterService {// 与原生端一致的 Channel 名称static const _channel = MethodChannel('samples.flutter.dev/native_counter');// 调用原生端的 increment 方法static Future<void> increment() async {try {await _channel.invokeMethod('increment');} on PlatformException catch (e) {print("Failed to increment: '${e.message}'.");}}// 调用原生端的 decrement 方法static Future<void> decrement() async {try {await _channel.invokeMethod('decrement');} on PlatformException catch (e) {print("Failed to decrement: '${e.message}'.");}}// 调用原生端的 getCurrentCount 方法并获取返回值static Future<int> getCurrentCount() async {try {final int count = await _channel.invokeMethod('getCurrentCount');return count;} on PlatformException catch (e) {print("Failed to get count: '${e.message}'.");return 0; // 出错时返回默认值}}
}
  1. 在 Flutter UI 中使用

main.dart

import 'package:flutter/material.dart';
import 'native_counter_service.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(home: const MyHomePage(),);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key});State<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;// 从原生端获取初始值void initState() {super.initState();_getCountFromNative();}_getCountFromNative() async {final count = await NativeCounterService.getCurrentCount();setState(() {_counter = count;});}// 增加计数_incrementCounter() async {await NativeCounterService.increment(); // 调用原生方法_getCountFromNative(); // 调用后重新获取最新值}// 减少计数_decrementCounter() async {await NativeCounterService.decrement(); // 调用原生方法_getCountFromNative(); // 调用后重新获取最新值}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Native ViewModel Example'),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('You have pushed the button this many times:',),Text('$_counter',style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: Column(mainAxisAlignment: MainAxisAlignment.end,children: [FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),),const SizedBox(height: 16),FloatingActionButton(onPressed: _decrementCounter,tooltip: 'Decrement',child: const Icon(Icons.remove),),],),);}
}

进阶:使用 EventChannel 实现主动推送(可选)

上面的例子是 Flutter 拉取 数据。如果你想实现原生端 推送 数据(例如,当 LiveData 变化时自动通知 Flutter),可以使用 EventChannel 来监听 LiveData。

这需要更多代码:

  1. 在 CounterViewModel 中暴露一个 Flow 或继续使用 LiveData。
  2. 在 MainActivity 中创建一个 EventChannel。
  3. 将 LiveData 转换为一个可供 EventChannel.StreamHandler 使用的 Flow。
  4. 在 Flutter 端监听这个 EventChannel 的流。

由于实现较为复杂,且大多数场景下 MethodChannel 的请求-响应模式已足够,这里不再展开。但如果你需要,可以搜索 Flutter EventChannel LiveData 找到相关教程。

总结

通过上述步骤,你成功地在 FlutterActivity 中使用了 Android ViewModel:

  1. 原生端 (Kotlin/Java):创建了 CounterViewModel 并在 MainActivity 中通过 MethodChannel 暴露其方法。
  2. 通信桥梁:定义了双方一致的 MethodChannel 名称和方法名 (increment, decrement, getCurrentCount)。
  3. Flutter 端 (Dart):创建了 NativeCounterService 来封装 Channel 的调用,并在 UI 中触发这些调用并更新状态。

这种模式非常强大,允许你将复杂的、平台相关的业务逻辑(如数据库操作、特定传感器数据访问、后台服务交互等)封装在原生端的 ViewModel 中,而 Flutter 只负责优雅的 UI 展示。

http://www.xdnf.cn/news/19993.html

相关文章:

  • SpringBoot+PDF.js实现按需分片加载(包含可运行样例源码)
  • C++小游戏
  • 腾讯开源HunyuanWorld-Voyager突破性原生3D重建与视频扩散框架
  • 计算机大数据毕业设计选题:基于Spark+hadoop的全球香水市场趋势分析系统
  • 优思学院|5个为什么(5 Whys)分析法一文讲清楚
  • AI编写自动点击器 - 毫秒级精准鼠标连点器
  • kafka:【1】概念关系梳理
  • kvm 虚拟机如何安装 qemu-guest-agent
  • kali_linux
  • 【Linux】线程封装
  • 【FastDDS】Layer DDS之Domain ( 04-DomainParticipantFactory)
  • 采用基于模型的方法实现车辆SOA威胁分析自动化
  • wpf 自定义密码文本框,并且可以双向绑定
  • 吱吱企业通讯软件以安全为核心,构建高效沟通与协作一体化平台
  • 什么是Agent?小白如何学习使用Agent?一篇文档带你详细了解神秘的Agent
  • 容器tomcat镜像制作
  • 算法题2:动态规划
  • Python委托迭代完全指南:从基础到高级设计模式实践
  • Vision Pro图像处理工具全解析
  • Hadoop HDFS-SecondaryNameNode(2nn)详细介绍
  • PPI网络与TF-miRNA调控网络的实现方法(基于《列腺癌研究.pdf》)
  • 跟做springboot尚品甄选项目
  • 理解用户需求
  • 第6章:垃圾回收分析与调优
  • Java内存模型解析:并发编程的基石
  • DARPA OFFSET公开资料探究
  • GEO优化专家孟庆涛:优质内容是GEO优化的核心
  • 后端一次性返回十万条数据时,前端需要采用多种性能优化策略来避免页面卡顿
  • 日志打印--idf的esp32
  • Agent开发基础---提示词编写