Code前端首页关于Code前端联系我们

Flutter项目如何将任务调度到后台线程?

terry 2年前 (2023-09-23) 阅读数 78 #移动小程序

在Android中,如果你想访问网络资源,但又不想阻塞主线程,避免ANR,通常会把任务放在后台线程中。例如,您可以使用 AsyncTask、LiveData、IntentService、JobScheduler 任务或使用调度程序通过 RxJava 管道将任务切换到后台线程。

因为Flutter使用单线程并运行事件循环(类似于),所以您不需要担心线程管理和创建后台线程。如果您正在执行 I/O 密集型任务,例如存储访问或网络请求,则可以安全无忧地使用 async/await。另一个例子,您需要执行使用 CPU 的计算密集型工作,那么您可以将其移至 Isolate,这样它就不会阻塞事件循环,就像您将任务放在 Android 主线程之外一样。

对于I/O密集型任务,将方法声明为异步,并在方法中等待长时间运行的任务:

content_copy

loadData() async {
 String dataURL = "";
 http.Response response = await http.get(dataURL);
 setState(() {
 widgets = ();
 });
}

这是您应该如何执行网络和数据库操作,所有这些操作都包括操作输入/输出。

在Android中,继承AsyncTask时,通常会重写三个方法,onPreExecute()、doInBackground()和onPostExecute()。 Flutter中没有对应的API。大部分时间你只需要等待方法调用,Dart 的事件循环将为你处理剩下的事情。

但是,有时您需要处理大量数据并挂起您的 UI。在 Flutter 中,您可以通过使用 Isolate 来利用多核处理器来执行耗时或计算密集型任务。

Isolate是独立执行的线程,不与主执行内存堆共享内存。这意味着您无法从主线程访问变量,或调用 setState() 来更新 UI。与 Android 中的线程不同,隔离,顾名思义,不能共享内存(例如通过静态变量)。

下面的示例展示了一个简单的 Isolate 如何将数据共享到主线程以更新 UI。

content_copy

loadData() async {
 ReceivePort receivePort = ReceivePort();
 await Isolate.spawn(dataLoader, );
 // The 'echo' isolate sends its SendPort as the first message.
 SendPort sendPort = await receivePort.first;
 List msg = await sendReceive(sendPort, "");
 setState(() {
 widgets = msg;
 });
}
// The entry point for the isolate.
static dataLoader(SendPort sendPort) async {
 // Open the ReceivePort for incoming messages.
 ReceivePort port = ReceivePort();
 // Notify any other isolates what port this isolate listens to.
 sendPort.send();
 await for (var msg in port) {
 String data = msg[0];
 SendPort replyTo = msg[1];
 String dataURL = data;
 http.Response response = await http.get(dataURL);
 // Lots of JSON to parse
 replyTo.send(());
 }
}
Future sendReceive(SendPort port, msg) {
 ReceivePort response = ReceivePort();
 ([msg, ]);
 return response.first;
}

DataLoader() 这里的 Isolate 在它自己的执行线程中运行。在 Isolate 中,您可以执行其他 CPU 密集型操作(例如解析大型 JSON 数据),或执行计算密集型数学操作(例如加密或信号处理)。

您可以打开下面的完整示例:

content_copy

import 'dart:convert';
import 'package:flutter/';
import 'package:http/' as http;
import 'dart:async';
import 'dart:isolate';
void main() {
 runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return MaterialApp(
 title: 'Sample App',
 theme: ThemeData(
 primarySwatch: ,
 ),
 home: SampleAppPage(),
 );
 }
}
class SampleAppPage extends StatefulWidget {
 SampleAppPage({Key key}) : super(key: key);
 @override
 _SampleAppPageState createState() =< _SampleAppPageState();
}
class _SampleAppPageState extends State>SampleAppPage< {
 List widgets = [];
 @override
 void initState() {
 ();
 loadData();
 }
 showLoadingDialog() {
 if (widgets.length == 0) {
 return true;
 }
 return false;
 }
 getBody() {
 if (showLoadingDialog()) {
 return getProgressDialog();
 } else {
 return getListView();
 }
 }
 getProgressDialog() {
 return Center(child: CircularProgressIndicator());
 }
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 appBar: AppBar(
 title: Text("Sample App"),
 ),
 body: getBody());
 }
 ListView getListView() =< ListView.builder(
 itemCount: widgets.length,
 itemBuilder: (BuildContext context, int position) {
 return getRow(position);
 });
 Widget getRow(int i) {
 return Padding(padding: (), child: Text("Row ${widgets[i]["title"]}"));
 }
 loadData() async {
 ReceivePort receivePort = ReceivePort();
 await Isolate.spawn(dataLoader, );
 // The 'echo' isolate sends its SendPort as the first message
 SendPort sendPort = await receivePort.first;
 List msg = await sendReceive(sendPort, "");
 setState(() {
 widgets = msg;
 });
 }
 // the entry point for the isolate
 static dataLoader(SendPort sendPort) async {
 // Open the ReceivePort for incoming messages.
 ReceivePort port = ReceivePort();
 // Notify any other isolates what port this isolate listens to.
 sendPort.send();
 await for (var msg in port) {
 String data = msg[0];
 SendPort replyTo = msg[1];
 String dataURL = data;
 http.Response response = await http.get(dataURL);
 // Lots of JSON to parse
 replyTo.send(());
 }
 }
 Future sendReceive(SendPort port, msg) {
 ReceivePort response = ReceivePort();
 ([msg, ]);
 return response.first;
 }
}

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门