Flutter动态观察与监听插件beholder的使用

Flutter动态观察与监听插件beholder的使用

简介

beholder 是一个用于 Flutter 的简单状态管理库。该库主要用于处理应用的状态变化,并能够自动更新依赖于这些状态变化的视图。

安装

首先,你需要在项目的 pubspec.yaml 文件中添加 beholder 插件:

dependencies:
  beholder: ^x.x.x

然后运行 flutter pub get 来安装它。

快速开始

步骤 1: 定义一个 ViewModel

ViewModel 用于封装状态和业务逻辑。例如,定义一个计数器的 ViewModel

class CounterViewModel extends ViewModel {
  late final counter = state(0);

  void increment() => counter.value++;
}

步骤 2: 监听状态变化

使用 Observer 来监听并自动更新视图。当 counter 的值发生变化时,视图会重新构建:

final vm = CounterViewModel();

Widget build(BuildContext context) {
  return Observer(
    builder: (context, watch) => OutlinedButton(
      onPressed: vm.increment,
      child: Text("${watch(vm.counter)}"),
    ),
  );
}

步骤 3: 处理异步数据

ViewModel 可以处理异步数据,通过 stateAsyncValue 类型来实现。例如,搜索用户时的状态管理:

class SearchUsersScreenVm extends ViewModel {
  late final search = state("");
  late final users = state(Loading<List<User>>());

  SearchUsersScreenVm() {
    search.listen((_, current) => refresh());
  }

  Future<void> refresh() async {
    users.value = Loading();
    try {
      final List<User> result = await Api.fetchUsers(search: search.value);
      users.value = Data(result);
    } catch (error) {
      users.value = Failure(error);
    }
  }
}

步骤 4: 释放资源

每次使用完 ViewModel 后,记得调用 dispose 方法来释放资源:

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

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final vm = SearchUsersScreenVm();

  @override
  Widget build(BuildContext context) {
    // 构建视图
  }

  @override
  void dispose() {
    vm.dispose();
    super.dispose();
  }
}

观察者模式

状态管理 (state)

statebeholder 中的核心概念之一。它能够跟踪其值的变化,并通知所有依赖它的观察者。

更新值

late final counter = state(0);
void increment() {
  counter.value = counter.value + 1;
  // 或者
  counter.update((current) => current + 1);
}

监听值的变化

counter.listen((previous, current) {
  // 对当前值进行处理
});

计算属性 (computed)

computed 用于从 state 中派生出新的值:

class User {
  final String name;
  User(this.name);
}

class UserProfileVm extends ViewModel {
  late final user = state<User?>(null);
  late final username = computed((watch) => watch(user)?.name ?? 'Guest');
}

参数化计算属性 (computedFactory)

如果需要参数化的计算属性,可以使用 computedFactory

class UserListVm extends ViewModel {
  late final users = state(<User>[]);
  late final usernameByIndex = computedFactory((watch, int index) {
    return watch(users)[index];
  });
}

// 使用
final vm = UserListVm();

Widget build(BuildContext context) {
  return ListView.builder(
    itemBuilder: (context, index) => Observer(
      builder: (context, watch) {
        final username = watch(vm.usernameByIndex(index));
        return Text(username);
      }
    )
  );
}

Observable 转换为 Stream

每个 Observable 都可以被转换为一个 Stream

class SearchScreenVm extends ViewModel {
  SearchScreenVm(this.githubApi) {
    final subscription = search.asStream().listen((value) {
      print("Search query changed to $value");
    });

    disposers.add(subscription.cancel);
  }

  late final search = state('');
}

工具类

异步值 (AsyncValue)

AsyncValue 用于处理异步数据,有三种子类型:

  • Data - 异步操作成功完成
  • Loading - 异步操作未完成
  • Failure - 异步操作出现错误
Widget build(BuildContext context) {
  return Observer(
    builder: (context, watch) {
      final posts = watch(vm.posts);
      if (posts case Loading(previousResult: Data(value: var posts))) {
        return Stack(
          children: [
            ListView.builder(
              itemCount: posts.length,
              itemBuilder: (context, index) => Text(posts[index].title),
            ),
            const CircularProgressIndicator(),
          ]
        );
      }

      // 其他逻辑
    }
  );
}

为什么使用 late 关键字?

late 关键字允许你在字段初始化时调用实例方法。例如:

class CounterViewModel extends ViewModel {
  late final counter = state(0);
}

这相当于:

class CounterViewModel extends ViewModel {
  final ObservableState<int> counter;
  CounterViewModel() : counter = ObservableState(0) {
    disposers.add(counter.dispose);
  }
}

更多关于Flutter动态观察与监听插件beholder的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter动态观察与监听插件beholder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


beholder 是一个用于 Flutter 的动态观察与监听插件,它可以帮助你在应用程序中监听和响应数据的变化。通过 beholder,你可以轻松地实现数据绑定、状态管理等功能。

安装 beholder

首先,你需要在 pubspec.yaml 文件中添加 beholder 依赖:

dependencies:
  flutter:
    sdk: flutter
  beholder: ^1.0.0  # 请根据最新版本号进行替换

然后运行 flutter pub get 来安装依赖。

使用 beholder

beholder 的核心概念是 Observable,它是一个可观察的对象,当它的值发生变化时,所有监听它的地方都会得到通知。

基本用法

  1. 创建 Observable

    你可以通过 Observable 类来创建一个可观察对象:

    import 'package:beholder/beholder.dart';
    
    void main() {
      var counter = Observable(0);
    }
    
  2. 监听 Observable

    你可以使用 listen 方法来监听 Observable 的变化:

    counter.listen((newValue) {
      print('Counter changed to $newValue');
    });
    
  3. 更新 Observable

    你可以通过 value 属性来更新 Observable 的值:

    counter.value = 1;  // 这将触发监听器
    

在 Flutter 中使用 beholder

beholder 可以很方便地与 Flutter 的 StatefulWidgetStatelessWidget 结合使用。你可以使用 ObservableBuilder 来构建 UI,当 Observable 的值发生变化时,UI 会自动更新。

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

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

class MyApp extends StatelessWidget {
  final counter = Observable(0);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Beholder Example')),
        body: Center(
          child: ObservableBuilder(
            observable: counter,
            builder: (context, value) {
              return Text('Counter: $value');
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            counter.value++;
          },
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

在这个例子中,ObservableBuilder 监听 counter 的变化,并在 counter 的值发生变化时自动更新 UI。

计算属性

beholder 还支持计算属性,你可以通过 Computed 类来创建一个基于其他 Observable 的计算属性:

var firstName = Observable('John');
var lastName = Observable('Doe');

var fullName = Computed(() => '${firstName.value} ${lastName.value}');

fullName.listen((newValue) {
  print('Full name changed to $newValue');
});

firstName.value = 'Jane';  // 这将触发 fullName 的监听器
回到顶部