Flutter Riverpod 状态管理深入分析

Flutter Riverpod 状态管理深入分析

本文档深入解析 Flutter Riverpod 状态管理库的核心原理、各类 Provider 的用法,并通过多个场景示例详细讲解实现方式。基于 riverpod: ^3.2.1 版本。


目录

  1. [Riverpod 是什么,为什么要用](#Riverpod 是什么,为什么要用 "#1-riverpod-%E6%98%AF%E4%BB%80%E4%B9%88%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8")
  2. 整体工作机制
  3. [Provider 类型详解](#Provider 类型详解 "#3-provider-%E7%B1%BB%E5%9E%8B%E8%AF%A6%E8%A7%A3")
  4. [Ref 与读取方式](#Ref 与读取方式 "#4-ref-%E4%B8%8E%E8%AF%BB%E5%8F%96%E6%96%B9%E5%BC%8F")
  5. [修饰符:family 与 autoDispose](#修饰符:family 与 autoDispose "#5-%E4%BF%AE%E9%A5%B0%E7%AC%A6family-%E4%B8%8E-autodispose")
  6. [Consumer 与 Widget 集成](#Consumer 与 Widget 集成 "#6-consumer-%E4%B8%8E-widget-%E9%9B%86%E6%88%90")
  7. [AsyncValue 与异步状态处理](#AsyncValue 与异步状态处理 "#7-asyncvalue-%E4%B8%8E%E5%BC%82%E6%AD%A5%E7%8A%B6%E6%80%81%E5%A4%84%E7%90%86")
  8. 场景一:基础计数器
  9. 场景二:异步用户资料
  10. 场景三:购物车与依赖组合
  11. [场景四:family 参数化](#场景四:family 参数化 "#11-%E5%9C%BA%E6%99%AF%E5%9B%9Bfamily-%E5%8F%82%E6%95%B0%E5%8C%96")
  12. 常见问题与最佳实践
  13. [Riverpod 3.2.x 版本要点](#Riverpod 3.2.x 版本要点 "#14-riverpod-32x-%E7%89%88%E6%9C%AC%E8%A6%81%E7%82%B9")
  14. 附录:快速参考

文档说明与版本基线

文中使用的包版本基线如下:

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^3.2.1
  riverpod_annotation: ^3.2.1  # 可选,用于代码生成

dev_dependencies:
  flutter_test:
    sdk: flutter
  riverpod_generator: ^3.2.1   # 可选,代码生成
  build_runner: ^2.4.0
  riverpod_lint: ^3.2.1        # 可选,静态分析

这些版本分别对应:

  • flutter_riverpod: ^3.2.1:本文中的 ProviderNotifierref.watchConsumerWidget 等用法按 Riverpod 3.x API 说明。
  • riverpod: ^3.2.1:核心包,由 flutter_riverpod 自动依赖。
  • Riverpod 3.2.1(2026-02-03)主要修复:恢复暂停的 provider 后可能不再通知监听器的 bug。

1. Riverpod 是什么,为什么要用

Riverpod 是由 Remi Rousselet 开发的响应式缓存与数据绑定框架,是 Provider 的继任者,旨在解决 Provider 的诸多限制。

一句话概括它的工作方式:

Provider 是"带缓存的函数",通过 ref 组合依赖、自动失效;UI 通过 ref.watch 订阅,状态变化时自动重建。

在以下场景里,Riverpod 往往比 Provider、BLoC 更合适:

  • 需要编译期安全 :Provider 依赖 BuildContext,Riverpod 不依赖,可在任意处使用
  • 需要多实例同类型:同一类型可有多个 Provider,通过变量名区分
  • 需要自动缓存与失效ref.watch 自动建立依赖,依赖变化时自动重建
  • 需要测试友好:所有 Provider 可 override,无需 Widget 树
  • 需要异步优先FutureProviderAsyncNotifierAsyncValue 原生支持
  • 需要自动释放autoDispose 在无监听时自动销毁状态

它的核心优势:

特性 说明
编译期安全 不依赖 BuildContext,可在 initState、测试、纯 Dart 中使用
响应式缓存 Provider 即"带缓存的函数",自动管理生命周期
依赖自动追踪 ref.watch 建立依赖图,依赖变化自动失效并重建
异步原生支持 FutureProvider、AsyncNotifier、AsyncValue 内置
可测试性 ProviderScope + overrides 轻松 mock
自动释放 autoDispose 无监听时自动 dispose
参数化 family 支持带参数的 Provider

2. 整体工作机制

2.1 数据流概览

text 复制代码
Provider 定义(带缓存的函数)
    ↓
ProviderScope(存储 Provider 状态)
    ↓
ref.watch / ref.read / ref.listen
    ↓
UI 重建 / 副作用 / 仅读取

2.2 核心概念

  • Provider:状态的描述,本质是"带缓存的函数",顶层声明,不可变
  • ProviderContainer :存储 Provider 实际状态,Flutter 中由 ProviderScope 创建
  • Ref :Provider 之间、Provider 与 UI 之间的桥梁,用于 watchreadlisteninvalidate
  • ConsumerConsumerWidgetConsumerConsumerStatefulWidget 等,提供 WidgetRef

ref 的来源 :在不同上下文中,ref 的获取方式不同,详见 [4.0 ref 的来源](#4.0 ref 的来源 "#40-ref-%E7%9A%84%E6%9D%A5%E6%BA%90")。

2.3 内部实现原理简述

Riverpod 的核心可以理解为:

  1. Provider 是纯函数描述:Provider 本身不可变,只是"如何计算值"的描述,不持有状态。
  2. ProviderContainer 持有实际状态 :每个 ProviderScope 对应一个 ProviderContainer,内部维护 Provider 的缓存与依赖图。
  3. Ref 是桥梁ref.watch 建立"当前计算 → 依赖的 Provider"的边,依赖变化时自动标记失效并触发重建。
  4. 懒加载 :Provider 首次被 watchread 时才执行 build 函数,之后返回缓存值。
  5. 依赖图驱动:当 A 依赖 B,B 变化时 A 自动失效,下次被访问时重新计算。

简化模型:

dart 复制代码
// 概念上,Provider 类似(ref 由框架注入):
class SimpleProvider<T> {
  T? _cache;
  final T Function(Ref ref) _build;

  T getValue(Ref ref) {
    if (_cache == null) _cache = _build(ref);
    return _cache!;
  }
}

真实实现会更复杂(依赖追踪、autoDispose、family 等),但核心思想是:带缓存的函数 + 依赖图驱动的自动失效

2.4 与 Provider 的对比

维度 Provider Riverpod
依赖 依赖 BuildContext、Widget 树 不依赖,可在任意处使用
多实例 同类型需不同 Provider 类型包装 同类型可有多个 Provider,变量名区分
测试 需要挂载 Widget 树 直接 ProviderContainer + overrides
异步 FutureProvider、StreamProvider 同上,另增 AsyncNotifier
缓存 需手动管理 内置缓存与自动失效

3. Provider 类型详解

Riverpod 提供 6 种 Provider 变体,按同步/异步/流式不可变/可变划分:

同步 Future Stream
不可变 Provider FutureProvider StreamProvider
可变 NotifierProvider AsyncNotifierProvider StreamNotifierProvider

3.1 Provider(同步、不可变)

最基础的 Provider,用于暴露不可变值或单例服务。ref 是回调函数的第一个参数,由框架在构建时注入。

dart 复制代码
// ref:Provider 回调的第一个参数
final helloWorldProvider = Provider((ref) => 'Hello world');

final apiClientProvider = Provider((ref) => ApiClient());

3.2 FutureProvider(异步、不可变)

用于一次性异步数据,如网络请求、本地存储读取。

dart 复制代码
final userProvider = FutureProvider<User>((ref) async {
  final api = ref.watch(apiClientProvider);
  return api.fetchUser();
});

消费时得到 AsyncValue<User>,可区分 loading、data、error。

3.3 StreamProvider(流式、不可变)

用于流式数据,如 WebSocket、Firebase、数据库监听。

dart 复制代码
final messagesProvider = StreamProvider<List<Message>>((ref) {
  return ref.watch(chatServiceProvider).messageStream;
});

3.4 NotifierProvider(同步、可变)

用于可变状态 ,用户交互后需要修改状态。替代旧的 StateNotifier

dart 复制代码
class CounterNotifier extends Notifier<int> {
  @override
  int build() => 0;

  void increment() => state++;
  void decrement() => state--;
}

final counterProvider = NotifierProvider<CounterNotifier, int>(CounterNotifier.new);

3.5 AsyncNotifierProvider(异步、可变)

用于异步初始化的可变状态,如需要先拉取数据再允许用户操作。

dart 复制代码
// ref:AsyncNotifier 基类提供的属性
class UserProfileNotifier extends AsyncNotifier<UserProfile> {
  @override
  Future<UserProfile> build() async {
    final api = ref.read(apiClientProvider);
    return api.fetchProfile();
  }

  Future<void> updateName(String name) async {
    state = const AsyncLoading();
    try {
      final profile = await ref.read(apiClientProvider).updateName(name);
      if (!ref.mounted) return;
      state = AsyncData(profile);
    } catch (e, st) {
      if (!ref.mounted) return;
      state = AsyncError(e, st);
    }
  }
}

final userProfileProvider = AsyncNotifierProvider<UserProfileNotifier, UserProfile>(UserProfileNotifier.new);

3.6 StreamNotifierProvider(流式、可变)

用于需要修改流的场景,较少使用。


4. Ref 与读取方式

4.0 ref 的来源

ref 是 Riverpod 注入的引用对象,用于访问 Provider、建立依赖、监听变化等。在不同上下文中,ref 的获取方式不同

上下文 ref 的来源 示例
Provider 回调 回调函数的第一个参数 Provider((ref) => ref.watch(...))
Notifier / AsyncNotifier 基类提供的 ref 属性 class X extends Notifier<T> { build() => ref.read(...) }
ConsumerWidget build 方法的第二个参数 WidgetRef ref Widget build(BuildContext context, WidgetRef ref)
ConsumerStatefulWidget ConsumerStateref 属性 class _MyState extends ConsumerState<MyPage> { ref.watch(...) }
Consumer builder 的第二个参数 Consumer(builder: (context, ref, _) => ...)
overrideWith / overrideWithBuild override 回调的参数 provider.overrideWith((ref) => value)
  • Provider 回调 :框架在首次构建 Provider 时调用你的函数,并传入 ref
  • Notifier / AsyncNotifier :继承基类后,this.ref 由框架在创建 Notifier 实例时注入,在 build() 和实例方法中均可使用。
  • Consumer 系列ConsumerWidgetConsumerStatefulWidgetConsumer 是 Riverpod 提供的桥接组件,将 ProviderScope 中的 ref 传给子组件。

4.1 ref.watch

作用 :监听 Provider,当值变化时触发当前 Widget 或 Provider 重建

dart 复制代码
class CounterDisplay extends ConsumerWidget {
  const CounterDisplay({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}
  • 适用于:需要根据状态更新 UI 的场景
  • 在 Provider 内使用:建立依赖,依赖变化时该 Provider 会重建

4.2 ref.read

作用 :仅读取当前值,不监听,不会因变化而重建。

dart 复制代码
FloatingActionButton(
  onPressed: () => ref.read(counterProvider.notifier).increment(),
  child: const Icon(Icons.add),
)
  • 适用于:事件回调、initState、一次性操作
  • ⚠️ 不要在 build 中用于需要监听的值 (应用 ref.watch

4.3 ref.listen

作用 :监听变化并执行副作用 ,不触发重建。类似 BlocListener

dart 复制代码
// 需在 ConsumerWidget / Consumer 的 build 中调用,才能使用 context
ref.listen<AsyncValue<User>>(userProvider, (previous, next) {
  next.whenOrNull(
    data: (user) => print('User loaded: $user'),
    error: (e, _) {
      if (context.mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Error: $e')),
        );
      }
    },
  );
});
  • 适用于:导航、SnackBar、Dialog 等一次性副作用
  • weak: true:不强制初始化 Provider,仅在有其他监听者时才初始化

4.4 ref.invalidate / ref.refresh

  • ref.invalidate(provider):标记 Provider 失效,下次被 watch 时重建,不立即重建
  • ref.refresh(provider):立即重建并返回新值
dart 复制代码
ref.invalidate(userProvider);  // 延迟重建,下次 watch 时重建
ref.refresh(userProvider);     // 立即重建;对 FutureProvider 返回 AsyncValue<T>

5. 修饰符:family 与 autoDispose

5.1 family(参数化)

用于根据参数创建不同实例,如按 ID 获取用户。

dart 复制代码
final userProvider = FutureProvider.family<User, String>((ref, userId) async {
  final api = ref.watch(apiClientProvider);
  return api.fetchUser(userId);
});

// 使用
ref.watch(userProvider('user-123'));

5.2 autoDispose(自动释放)

当 Provider 不再被监听时,自动销毁其状态,释放资源。

dart 复制代码
final searchResultsProvider = FutureProvider.autoDispose<List<Product>>((ref) async {
  final query = ref.watch(searchQueryProvider);
  return ref.read(apiClientProvider).search(query);
});
  • 适用:页面级、列表项级等短期状态
  • ref.keepAlive():在 autoDispose 的 Provider 内调用,可阻止自动释放
  • ref.onDispose():注册 dispose 时的清理逻辑

5.3 组合使用

dart 复制代码
final productProvider = FutureProvider.autoDispose.family<Product, String>((ref, id) async {
  return ref.read(apiClientProvider).fetchProduct(id);
});

6. Consumer 与 Widget 集成

6.1 ConsumerWidget

无状态 Widget,build 方法多一个 WidgetRef ref 参数(即 ref 的来源)。

dart 复制代码
class MyPage extends ConsumerWidget {
  const MyPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Scaffold(
      body: Center(child: Text('$count')),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).increment(),
        child: const Icon(Icons.add),
      ),
    );
  }
}

6.2 ConsumerStatefulWidget

有状态 Widget,ref 来自 ConsumerState 基类,在 initStatebuild 等生命周期中均可使用。

dart 复制代码
class MyPage extends ConsumerStatefulWidget {
  const MyPage({super.key});

  @override
  ConsumerState<MyPage> createState() => _MyPageState();
}

// ref:ConsumerState 基类提供的属性
class _MyPageState extends ConsumerState<MyPage> {
  @override
  void initState() {
    super.initState();
    Future.microtask(() {
      ref.read(someProvider.notifier).fetch();
    });
  }

  @override
  Widget build(BuildContext context) {
    final data = ref.watch(someProvider);
    return Text('$data');
  }
}

6.3 Consumer

在任意 Widget 的 build 中嵌入,ref 来自 builder 的第二个参数。

dart 复制代码
// ref:Consumer 的 builder 第二个参数
class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, _) {
        final value = ref.watch(myProvider);
        return Text('$value');
      },
    );
  }
}

6.4 ProviderScope

应用根节点必须包裹 ProviderScope,用于存储 Provider 状态。

dart 复制代码
void main() {
  runApp(
    ProviderScope(
      child: const MyApp(),
    ),
  );
}

7. AsyncValue 与异步状态处理

FutureProviderAsyncNotifierProvider 暴露的值类型为 AsyncValue<T>

7.1 AsyncValue 三种状态

  • AsyncLoading:加载中,可携带 previous 用于刷新时保留旧数据
  • AsyncData<T>:成功,包含 value
  • AsyncError:失败,包含 errorstackTrace

7.2 常用 API

dart 复制代码
// 模式匹配
asyncValue.when(
  data: (data) => Text('$data'),
  loading: () => const CircularProgressIndicator(),
  error: (e, st) => Text('Error: $e'),
);

// 简化版
asyncValue.whenOrNull(
  data: (data) => Text('$data'),
);

// 获取值,loading/error 时抛错
final value = asyncValue.requireValue;

// 获取值,error 时返回 null
final value = asyncValue.value;

// 判断
asyncValue.hasValue;
asyncValue.hasError;
asyncValue.isLoading;
asyncValue.isReloading;  // 刷新中(有旧数据)

7.3 结合 ref.watch 组合异步 Provider

Riverpod 3.1+ 支持在 FutureProvider 内使用 AsyncValue.requireValue 同步组合异步 Provider:

dart 复制代码
final sumProvider = FutureProvider<int>((ref) async {
  AsyncValue<int> a = ref.watch(aProvider);
  AsyncValue<int> b = ref.watch(bProvider);
  // requireValue 在 loading/error 时会抛错,需确保依赖已就绪
  return a.requireValue + b.requireValue;
});

8. 场景一:基础计数器

8.1 定义 Notifier

dart 复制代码
class CounterNotifier extends Notifier<int> {
  @override
  int build() => 0;

  void increment() => state++;
  void decrement() => state--;
}

final counterProvider = NotifierProvider<CounterNotifier, int>(CounterNotifier.new);

8.2 注入与消费

dart 复制代码
void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends ConsumerWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Counter')),
        body: Center(
          child: Text('${ref.watch(counterProvider)}'),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => ref.read(counterProvider.notifier).increment(),
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

9. 场景二:异步用户资料

9.1 AsyncNotifier 实现

dart 复制代码
class UserProfileNotifier extends AsyncNotifier<UserProfile> {
  @override
  Future<UserProfile> build() async {
    final api = ref.read(apiClientProvider);
    return api.fetchProfile();
  }

  Future<void> refresh() async {
    state = const AsyncLoading();
    try {
      final profile = await ref.read(apiClientProvider).fetchProfile();
      if (!ref.mounted) return;
      state = AsyncData(profile);
    } catch (e, st) {
      if (!ref.mounted) return;
      state = AsyncError(e, st);
    }
  }
}

final userProfileProvider = AsyncNotifierProvider<UserProfileNotifier, UserProfile>(
  UserProfileNotifier.new,
);

9.2 UI 消费

dart 复制代码
class ProfilePage extends ConsumerWidget {
  const ProfilePage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final profile = ref.watch(userProfileProvider);

    return profile.when(
      data: (data) => Column(
        children: [
          Text(data.name),
          Text(data.email),
          ElevatedButton(
            onPressed: () => ref.read(userProfileProvider.notifier).refresh(),
            child: const Text('刷新'),
          ),
        ],
      ),
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (e, st) => Center(child: Text('错误: $e')),
    );
  }
}

10. 场景三:购物车与依赖组合

10.1 模型与多 Provider 依赖

dart 复制代码
class CartItem {
  final String id;
  final String name;
  final double price;
  final int quantity;

  CartItem({required this.id, required this.name, required this.price, this.quantity = 1});
}

final cartProvider = NotifierProvider<CartNotifier, List<CartItem>>(CartNotifier.new);

final cartItemCountProvider = Provider<int>((ref) {
  return ref.watch(cartProvider).fold<int>(0, (sum, item) => sum + item.quantity);
});

final cartTotalProvider = Provider<double>((ref) {
  return ref.watch(cartProvider).fold<double>(
    0,
    (sum, item) => sum + item.price * item.quantity,
  );
});

10.2 CartNotifier 实现

dart 复制代码
class CartNotifier extends Notifier<List<CartItem>> {
  @override
  List<CartItem> build() => [];

  void add(CartItem item) {
    state = [...state, item];
  }

  void remove(String id) {
    state = state.where((i) => i.id != id).toList();
  }
}

11. 场景四:family 参数化

11.1 按 ID 获取详情

dart 复制代码
final productDetailProvider = FutureProvider.autoDispose.family<Product, String>(
  (ref, productId) async {
    final api = ref.watch(apiClientProvider);
    return api.fetchProduct(productId);
  },
);

// 使用
class ProductDetailPage extends ConsumerWidget {
  const ProductDetailPage({required this.productId, super.key});
  final String productId;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final product = ref.watch(productDetailProvider(productId));
    return product.when(
      data: (p) => Text(p.name),
      loading: () => const CircularProgressIndicator(),
      error: (e, _) => Text('$e'),
    );
  }
}

12. 常见问题与最佳实践

12.1 initState 中访问 Provider

ConsumerStatefulWidgetref 下使用 ref.read,且若会同步触发状态更新,用 Future.microtask 推迟:

dart 复制代码
@override
void initState() {
  super.initState();
  Future.microtask(() {
    ref.read(userProfileProvider.notifier).refresh();
  });
}

12.2 避免在 build 中用 ref.read 监听

需要监听时用 ref.watch,否则不会重建。

12.3 异步操作后检查 ref.mounted

AsyncNotifierNotifier 的异步方法中,await 之后更新 state 前应检查 ref.mounted

dart 复制代码
Future<void> loadData() async {
  final data = await api.fetch();
  if (!ref.mounted) return;  // 已 dispose 则不再更新
  state = AsyncData(data);
}

12.4 合理使用 autoDispose

  • 页面级、列表项级:建议 autoDispose
  • 全局单例、用户信息:通常不用 autoDispose

12.5 项目结构建议

bash 复制代码
lib/
  app/
    app.dart
    providers/          # 全局 Provider
  features/
    auth/
      providers/
      notifiers/
      views/
    cart/
      providers/
      notifiers/
      views/

13. Riverpod 3.2.x 版本要点

13.1 3.2.1 修复

  • 修复恢复暂停的 provider 后可能不再通知监听器的 bug

13.2 3.2.0 变更

  • 修复 selectAsync 取消订阅时可能抛错
  • 修复 ref.mounted 在 provider 重建后对陈旧 ref 仍返回 true 导致竞态
  • 修复 Notifier 在依赖变化时丢失状态的回归
  • 新增 Ref.isPaused 检查是否有活跃监听者
  • family.overrideWith 弃用,改用 family.overrideWith2

13.3 3.x 与 2.x 主要差异

  • StateNotifierProviderStateProvider 移至 legacy.dart,推荐使用 NotifierProvider
  • Ref 子类(如 FutureProviderRef)移除,统一使用 Ref
  • Provider.autoDispose() 可写为 Provider(isAutoDispose: true)
  • 所有 Provider 默认用 == 比较值并过滤重复更新

14. 附录:快速参考

操作 代码
创建 Provider Provider((ref) => value)
创建 Notifier NotifierProvider<X, T>(X.new)
创建 AsyncNotifier AsyncNotifierProvider<X, T>(X.new)
监听并重建 ref.watch(provider)
只读不监听 ref.read(provider)
监听并副作用 ref.listen(provider, (prev, next) {})
失效 ref.invalidate(provider)
立即刷新 ref.refresh(provider)
参数化 Provider.family<T, Arg>((ref, arg) => ...)
自动释放 Provider.autoDispose((ref) => ...)
根节点 ProviderScope(child: MyApp())

参考资源


总结

整篇文档可以归纳成一句话:

Riverpod 是一套"Provider 即带缓存的函数 + 依赖图驱动自动失效"的响应式状态管理框架。

如果你的 Flutter 项目需要:

  • 编译期安全:不依赖 BuildContext,可在任意处使用
  • 异步优先:FutureProvider、AsyncNotifier、AsyncValue 原生支持
  • 可测试性:override 任意 Provider,无需 Widget 树
  • 自动缓存与失效ref.watch 自动建立依赖,依赖变化自动重建
  • 多实例同类型:同一类型可有多个 Provider

那么 Riverpod 非常推荐使用

相关推荐
Justin在掘金1 小时前
Flutter BLoC 状态管理框架深入分析
flutter
weixin_443478512 小时前
flutter组件学习之Cupertino 组件(iOS风格)
学习·flutter·ios
国医中兴3 小时前
Flutter 三方库 superclass 的鸿蒙化适配指南 - 支持原生高性能类构造、属性代理与深层元数据解析实战
flutter·harmonyos·鸿蒙·openharmony
Swift社区3 小时前
Flutter 迁移鸿蒙 ArkUI 的真实成本
flutter·华为·harmonyos
牛马11116 小时前
Flutter CustomPainter
flutter
蜡台17 小时前
Flutter 安装配置
android·java·flutter·环境变量
加农炮手Jinx17 小时前
Flutter 组件 ubuntu_service 适配鸿蒙 HarmonyOS 实战:底层系统服务治理,构建鸿蒙 Linux 子系统与守护进程交互架构
flutter·harmonyos·鸿蒙·openharmony·ubuntu_service
里欧跑得慢17 小时前
Flutter 三方库 mobx_codegen — 自动化驱动的高性能响应式状态管理(适配鸿蒙 HarmonyOS Next ohos)
flutter·自动化·harmonyos
王码码203517 小时前
Flutter 三方库 login_client 的鸿蒙化适配指南 - 打造工业级安全登录、OAuth2 自动化鉴权、鸿蒙级身份守门员
flutter·harmonyos·鸿蒙·openharmony·login_client