Flutter远程控制插件flutter_remoter的使用

Flutter远程控制插件flutter_remoter的使用

特性

  • 全局和单独选项
  • 如果没有监听器,缓存会在缓存时间后被收集
  • 如果查询过期,会重新获取数据
  • 当多个小部件同时挂载时,只会获取一次数据
  • 分页
  • 使查询无效
  • 手动设置查询数据
  • 当新小部件挂载时重试查询
  • 自动重试,指数退避策略
  • 变更小部件

开始使用

安装依赖

pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter_remoter: ^0.2.0

包裹你的应用

包裹你的应用需要使用RemoterProvider并传入一个RemoterClient实例。RemoterClient可以用于整个应用。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return RemoterProvider(
      client: RemoterClient(
        // 这一行定义了所有查询的默认选项
        // 您可以在每个查询中覆盖这些选项
        options: RemoterOptions(
            // staleTime 定义了查询获取后的多少毫秒内可以重新获取
            // 使用无限的staleTime如果不需要在新的查询挂载时重新获取数据
            // 1 << 31 是最大int32
            // 默认是0毫秒
            staleTime: 0,
            // cacheTime 定义了在所有监听器消失后的多少毫秒内清除查询数据
            // 默认是5分钟
            cacheTime: 5 * 60 * 1000,
            // 最大重试延迟(毫秒)
            maxDelay: 5 * 60 * 1000,
            // 最大重试次数
            maxRetries: 3,
            // 标志决定错误状态的查询是否在挂载时重新获取
            retryOnMount: true,
        ),
      ),
      child: const MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

使用

RemoterQuery

用于获取单个页面的数据。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: RemoterQuery&lt;List&lt;String&gt;&gt;(
          // remoterKey 应该是唯一的
          remoterKey: "numbers",
          execute: () async {
            return List.generate(12, (index) =&gt; (index + 1).toString());
          },
          builder: (context, snapshot, utils) {
            if (snapshot.status == RemoterStatus.idle) {
              // 您可以跳过此检查如果您不使用disabled参数
            }
            if (snapshot.status == RemoterStatus.fetching) {
              return const Center(
                child: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: CircularProgressIndicator(),
                ),
              );
            }
            if (snapshot.status == RemoterStatus.error) {
              return Container(
                alignment: Alignment.center,
                padding: const EdgeInsets.symmetric(vertical: 16),
                child: Column(
                  children: [
                    const Text(
                      "Error occured",
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                    ElevatedButton(
                        child: const Text("retry"),
                        onPressed: () {
                          utils.retry();
                        }),
                  ],
                ),
              );
            }
            // 这里可以安全地使用snapshot.data!
            return Container(
              alignment: Alignment.topCenter,
              child: GridView(
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                ),
                children: snapshot.data!
                    .map(
                      (text) =&gt; Text(
                        text,
                        textAlign: TextAlign.center,
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 24,
                        ),
                      ),
                    )
                    .toList(),
              ),
            );
          }),
    );
  }
}

PaginatedRemoterQuery

用于具有多页或类似“无限滚动”的数据。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: PaginatedRemoterQuery&lt;List&lt;String&gt;&gt;(
          // remoterKey 应该是唯一的
          remoterKey: "numbers",
          getNextPageParam: (pages) {
            return pages[pages.length - 1] + 1;
          },
          getPreviousPageParam: (pages) {
            return pages[0] - 1;
          },
          execute: (param) async {
            return List.generate(param, (index) =&gt; (index + 1).toString());
          },
          builder: (context, snapshot, utils) {
            if (snapshot.status == RemoterStatus.idle) {
              // 您可以跳过此检查如果您不使用disabled参数
            }
            if (snapshot.status == RemoterStatus.fetching) {
              return const Center(
                child: Padding(
                  padding: EdgeInsets.all(8.0),
                  child: CircularProgressIndicator(),
                ),
              );
            }
            if (snapshot.status == RemoterStatus.error) {
              return Container(
                alignment: Alignment.center,
                padding: const EdgeInsets.symmetric(vertical: 16),
                child: Column(
                  children: [
                    const Text(
                      "Error occured",
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                    ElevatedButton(
                        child: const Text("retry"),
                        onPressed: () {
                          utils.retry();
                        }),
                  ],
                ),
              );
            }
            // 这里可以安全地使用snapshot.data!
            return SingleChildScrollView(
              child: Column(
                children: [
                  if (snapshot.hasPreviousPage)
                    ElevatedButton(
                      onPressed: () {
                        utils.fetchPreviousPage();
                      },
                      child: snapshot.isFetchingPreviousPage == true
                          ? const CircularProgressIndicator(
                                color: Colors.white,
                            )
                          : const Text("Load previous"),
                    ),
                  ...snapshot.data!
                      .expand((el) =&gt; el)
                      .map(
                        (d) =&gt; Text(d),
                      )
                      .toList(),
                  if (snapshot.hasNextPage)
                    ElevatedButton(
                      onPressed: () {
                        utils.fetchNextPage();
                      },
                      child: snapshot.isFetchingNextPage == true
                          ? const CircularProgressIndicator(
                              color: Colors.white,
                            )
                          : const Text("Load more"),
                    ),
                ],
              ),
            );
          }),
    );
  }
}

RemoterMutation

用于简化处理异步调用。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: RemoterMutation&lt;String, String&gt;(
        execute: (param) async {
          await Future.delayed(const Duration(seconds: 1));
          return "Mutation executed with param: $param";
        },
        builder: (context, snapshot, utils) {
          if (snapshot.status == RemoterStatus.idle) {
            // Mutation hasn't started yet
          }
          if (snapshot.status == RemoterStatus.fetching) {
            // Handle fetching state here
          }
          if (snapshot.status == RemoterStatus.error) {
            // Handle error here
          }
          // It is okay to use snapshot.data! here
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                snapshot.data ?? "",
                style: const TextStyle(fontSize: 24),
              ),
              const SizedBox(height: 16),
              FloatingActionButton(
                onPressed: snapshot.status == RemoterStatus.fetching
                    ? null
                    : () {
                        // Starts mutation
                        // In this case null will be passed to execute as param
                        utils.mutate("Test");
                      },
                child: const Icon(Icons.add),
              ),
            ],
          );
        },
      ),
    );
  }
}

使用RemoterClient

有两种方法来获取RemoterClient实例。

使用BuildContext

RemoterProvider.of(context).client

不使用BuildContext

为了在不使用BuildContext的情况下使用RemoterClient,您可以创建一个RemoterClient实例并在单独的文件中导入它。然后将该实例传递给RemoterProvider,这样您就可以在应用的任何地方使用它。

// 在单独的文件中创建 RemoterClient 实例
import 'path_to_RemoterClient_instance';

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return RemoterProvider(
      // 'client' 是从导入的实例
      client: client,
      child: const MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

更多关于Flutter远程控制插件flutter_remoter的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter远程控制插件flutter_remoter的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_remoter 是一个用于 Flutter 的远程控制插件,它允许你通过网络远程控制其他设备或应用。这个插件通常用于实现远程桌面、远程控制设备等功能。以下是如何使用 flutter_remoter 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  flutter_remoter: ^0.1.0  # 请根据实际版本号填写

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

2. 导入插件

在你的 Dart 文件中导入 flutter_remoter 插件:

import 'package:flutter_remoter/flutter_remoter.dart';

3. 初始化插件

在使用插件之前,通常需要先进行初始化。你可以通过以下方式初始化 flutter_remoter

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterRemoter.initialize();
  runApp(MyApp());
}

4. 创建远程控制连接

你可以通过 FlutterRemoter 类来创建一个远程控制连接。假设你有一个服务器地址和端口,你可以这样连接:

Future<void> connectToRemote() async {
  try {
    await FlutterRemoter.connect('192.168.1.100', 8080);
    print('Connected to remote device');
  } catch (e) {
    print('Failed to connect: $e');
  }
}

5. 发送控制命令

连接成功后,你可以发送控制命令到远程设备。例如,发送一个鼠标点击事件:

void sendMouseClick() {
  FlutterRemoter.sendMouseEvent(100, 100, MouseEventType.click);
}

6. 处理远程事件

你还可以监听来自远程设备的事件。例如,监听键盘输入:

void listenToKeyboardEvents() {
  FlutterRemoter.onKeyboardEvent.listen((event) {
    print('Key pressed: ${event.key}');
  });
}

7. 断开连接

当你不再需要远程控制时,可以断开连接:

void disconnect() async {
  await FlutterRemoter.disconnect();
  print('Disconnected from remote device');
}

8. 示例代码

以下是一个简单的示例代码,展示了如何使用 flutter_remoter 插件进行远程控制:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterRemoter.initialize();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter Remoter Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: connectToRemote,
                child: Text('Connect to Remote'),
              ),
              ElevatedButton(
                onPressed: sendMouseClick,
                child: Text('Send Mouse Click'),
              ),
              ElevatedButton(
                onPressed: disconnect,
                child: Text('Disconnect'),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> connectToRemote() async {
    try {
      await FlutterRemoter.connect('192.168.1.100', 8080);
      print('Connected to remote device');
    } catch (e) {
      print('Failed to connect: $e');
    }
  }

  void sendMouseClick() {
    FlutterRemoter.sendMouseEvent(100, 100, MouseEventType.click);
  }

  void disconnect() async {
    await FlutterRemoter.disconnect();
    print('Disconnected from remote device');
  }
}
回到顶部