Flutter长时间任务处理插件android_long_task的使用

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

Flutter长时间任务处理插件android_long_task的使用

插件介绍

android_long_task 是是一个用于在 Android 前景服务中运行 Dart 代码的 Flutter 插件。它允许你在后台执行长时间的任务,而不会影响主应用界面。

是否支持 iOS?

iOS 不支持此插件,因为 iOS 对于背景服务有严格的限制。为了绕过这些限制,你需要考虑更改设计或需求。

插件工作原理

  1. Activity 和 Service:

    • Flutter 应用在 Android 上运行时,会作为一个 Activity 运行。
    • Service 是是另一种 Android 组件,可以在后台运行代码,但不能运行很长时间。
    • Foreground Service 是是一种特殊的 Service,它不会被系统杀死,并且需要显示通知给用户。
  2. Dart 代码执行环境:

    • MainActivity 中的 Dart 代码和 serviceMain 函数中的 Dart 代码分别运行在不同的环境中(进程)。
    • 因此,MainActivity 中的代码与 serviceMain 函数中的代码执行方式不同。

使用步骤

Step 1: 创建 Service 共享数据

创建一个 ServiceData 类来指定共享数据,包括 ForegroundService 的的通知标题和描述。

import 'dart:convert';
import 'package:android_long_task/android_long_task.dart';

class SharedUploadData extends ServiceData {
  int progress = 0;

  [@override](/user/override)
  String get notificationTitle => 'uploading';

  [@override](/user/override)
  String get notificationDescription => 'progress -> $progress';

  String toJson() {
    var map = {
      'progress': progress,
    };
    return jsonEncode(map);
  }

  static AppServiceData fromJson(Map<String, dynamic> json) {
    return AppServiceData()..progress = json['progress'] as int;
  }
}
Step 2: 创建 serviceMain 函数

lib/main.dart 文件中创建 serviceMain 函数,定义将在前景服务中运行的 Dart 代码。确保函数上标注了 [@pragma](/user/pragma)('vm:entry-point')

// 这个整个函数在你的前景服务中运行
[@pragma](/user/pragma)('vm:entry-point')
serviceMain() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 设置回调并定义你希望在前景服务运行时执行的代码
  ServiceClient.setExecutionCallback((initialData) async {
    // 当你从应用程序代码调用 `AppClient.execute()` 时设置初始数据
    var serviceData = AppServiceData.fromJson(initialData);
    // 在这里运行你的代码
    serviceData.progress = 20;
    await ServiceClient.update(serviceData);
    // 运行更多的代码
    serviceData.progress = 100;
    await ServiceClient.endExecution(serviceData);
    await ServiceClient.stopService();    
  });
}
Step 3: 执行

从应用程序 Dart 代码中调用 AppClient.execute() 来启动前景服务并运行 serviceMain 函数。

import 'package:android_long_task/android_long_task.dart';

// 可以监听共享数据更新
AppClient.updates.listen((json) {
  if ( (json != null) {
    var serviceDataUpdate = AppServiceData.fromJson(json);
    // 你的代码
  }
});

var resultJson = await AppClient.execute(initialSharedData);
var serviceDataResult = AppServiceData.fromJson(resultJson); 

注意事项

  • ServiceClient 应仅在 serviceMain 函数中使用。
  • 确保 ic_launcher.png 存在于 android/app/src/main/res/mipmap 目录下作为 Foreground Service 的的通知图标。

示例代码

import 'package:flutter/material.dart';
import 'package:android_long_task/android_long_task.dart';
import 'app_service_config.dart';

AppServiceData data = AppServiceData();

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'my foreground service example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'android long task example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({required this.title});
  final String title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _result = 'result';
  String _status = 'status';

  [@override](/user/override)
  void initState() {
    AppClient.updates.listen((json) {
      if (json != null) {
        var serviceData = AppServiceData.fromJson(json);
        setState(() {
          _status = serviceData.notificationDescription;
        });
      }
    });
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('$_status', textAlign: TextAlign.center),
            SizedBox(height: 6),
            Text('$_result',
                textAlign: TextAlign.center,
                style: Theme.of(context).textTheme.headline6),
            SizedBox(height: 60),
            ElevatedButton(
              onPressed: () async {
                try {
                  var result = await AppClient.execute(data);
                  var resultData = AppServiceData.fromJson(result);
                  setState(() {
                    _result =
                        'finished executing service process ;) -&gt; ${resultData.progress}';
                  });
                } on PlatformException catch (e, stacktrace) {
                  print(e);
                  print(stacktrace);
                }
              },
              child: Text('run dart function'),
            ),
            ElevatedButton(
              onPressed: () async {
                try {
                  var result = await AppClient.getData();
                  setState(() {
                    _result = result.toString();
                  });
                } on PlatformException catch (e, stacktrace) {
                  print(e);
                  print(stacktrace);
                }
              },
              child: Text('get service data'),
            ),
            ElevatedButton(
              onPressed: () async {
                try {
                  await AppClient.stopService();
                  setState(() {
                    _result = 'stop service';
                  });
                } on PlatformException catch (e, stacktrace) {
                  print(e);
                  print(stacktrace);
                }
              },
              child: Text('stop service'),
            ),
          ],
        ),
      ),
    );
  }
}

[@pragma](/user/pragma)('vm:entry-point')
serviceMain() async {
  WidgetsFlutterBinding.ensureInitialized();
  ServiceClient.setExecutionCallback((initialData) async {
    var serviceData = AppServiceData.fromJson(initialData);
    for (var i = 0; i &lt; 50; i++) {
      print('dart -&gt; $i');
      serviceData.progress = i;
      await ServiceClient.update(serviceData);
      if (i &gt; 5) {
        await ServiceClient.endExecution(serviceData);
        var result = await ServiceClient.stopService();
        print(result);
      }
      await Future.delayed(const Duration(seconds: 1));
    }
  });
}

更多关于Flutter长时间任务处理插件android_long_task的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter长时间任务处理插件android_long_task的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用android_long_task插件来处理长时间任务的示例代码。这个插件允许你在Android平台上执行长时间运行的任务而不阻塞主线程。

首先,确保你已经在pubspec.yaml文件中添加了android_long_task依赖:

dependencies:
  flutter:
    sdk: flutter
  android_long_task: ^x.y.z  # 请替换为最新的版本号

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

接下来,在你的Flutter项目中,你可以按照以下步骤使用android_long_task插件:

  1. 导入插件

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

import 'package:android_long_task/android_long_task.dart';
  1. 定义长时间运行的任务

定义一个函数,该函数将包含你想要在后台执行的任务。例如,一个模拟的长时间运行任务:

Future<void> longRunningTask() async {
  await Future.delayed(Duration(seconds: 10)); // 模拟长时间任务
  print("Long running task completed!");
}
  1. 使用AndroidLongTask执行后台任务

使用AndroidLongTask来启动后台任务。注意,这个API只在Android平台上可用,因此你可能需要做一些平台检查。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:android_long_task/android_long_task.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Long Task Example'),
        ),
        body: Center(
          child: LongTaskButton(),
        ),
      ),
    );
  }
}

class LongTaskButton extends StatefulWidget {
  @override
  _LongTaskButtonState createState() => _LongTaskButtonState();
}

class _LongTaskButtonState extends State<LongTaskButton> {
  void _startLongTask() async {
    if (Platform.isAndroid) {
      try {
        await AndroidLongTask.execute(() async {
          await longRunningTask();
          // 任务完成后可以通知UI线程,这里简单打印
          print("Notified UI thread that task is complete");
        });
      } catch (e) {
        print("Error executing long task: $e");
      }
    } else {
      // 对于非Android平台,可以在这里处理或者简单提示
      print("Long tasks are only supported on Android.");
      longRunningTask(); // 直接在主线程执行(不推荐,仅用于演示)
    }
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _startLongTask,
      child: Text('Start Long Task'),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮。当用户点击按钮时,如果运行在Android平台上,AndroidLongTask.execute方法将被调用以在后台执行longRunningTask函数。任务完成后,你可以在控制台中看到打印的消息。

请注意,AndroidLongTask.execute方法接受一个Future<void>函数作为参数,这意味着你可以在其中执行任何异步操作。然而,由于它是在后台线程上运行的,因此你不能直接更新UI。如果你需要在任务完成后更新UI,你可以考虑使用状态管理(如ProviderBlocRiverpod)或者通过某种机制(如Completer或事件总线)来通知UI线程。

希望这个示例能帮助你理解如何在Flutter项目中使用android_long_task插件来处理长时间任务。

回到顶部