flutter实现异步UI

举报
yd_221104950 发表于 2020/12/02 22:45:33 2020/12/02
【摘要】 1.runOnUiThread 在Flutter中等价于什么 Dart是单线程执行模型,支持Isolates(在另一个线程上运行Dart代码的方式)、事件循环和异步编程。 除非您启动一个Isolate,否则您的Dart代码将在主UI线程中运行,并由事件循环驱动。可以在UI线程上运行网络请求代码而不会导致UI挂起,因为网络请求是异步的: loadData() asyn...

1.runOnUiThread 在Flutter中等价于什么

Dart是单线程执行模型,支持Isolates(在另一个线程上运行Dart代码的方式)、事件循环和异步编程。 除非您启动一个Isolate,否则您的Dart代码将在主UI线程中运行,并由事件循环驱动。可以在UI线程上运行网络请求代码而不会导致UI挂起,因为网络请求是异步的:

loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; try{ Response response = await Dio().get(dataURL,options: Options(responseType: ResponseType.json),); setState(() {// 更新UI json = response.data; }); }catch(e){ print(e); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

要更新UI,可以调用setState,这会触发build方法再次运行并更新数据。

2.AsyncTask和IntentService在Flutter中等价于什么

在Android中,当你想访问一个网络资源时,你通常会创建一个AsyncTask,它将在UI线程之外运行代码来防止你的UI被阻塞。 AsyncTask有一个线程池,可以为你管理线程。

由于Flutter是单线程的,运行一个事件循环(如Node.js),所以您不必担心线程管理或者使用AsyncTasks、IntentServices。

要异步运行代码,可以将函数声明为异步函数,并在该函数中等待这个耗时任务:

loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; try{ Response response = await Dio().get(dataURL,options: Options(responseType: ResponseType.json),); setState(() {// 更新UI json = response.data; }); }catch(e){ print(e); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这就是典型的进行网络或数据库调用的方式

在Android上,当您继承AsyncTask时,通常会覆盖3个方法,OnPreExecute、doInBackground和onPostExecute。 在Flutter中没有这种模式的等价物,只需等待一个长时间运行的函数,而Dart的事件循环将负责其余的事情。

但是,有时可能需要处理大量数据,导致UI可能会挂起。在Flutter中,可以利用多个CPU内核来执行耗时或计算密集型任务。 这是通过使用Isolates来完成的。

是一个独立的执行线程,它运行时不会与主线程共享任何内存。这意味着你不能从该线程访问变量或通过调用setState来更新你的UI。

Isolate的例子,以及如何与主线程通信和共享数据以更新UI:

List messages;
  loadData() async { // 当前线程的信息的接收者 ReceivePort receivePort = new ReceivePort(); /** * 创建并生成与当前隔离共享相同代码的隔离。 * Isolate.spawn 接受的方法必须是静态的或是一个顶层函数 * 传递当前接收者receivePort.sendPort给其他线程,那么其他线程就可以通过它,与当前线程通信 * */ await Isolate.spawn(dataLoader, receivePort.sendPort); SendPort sendPort = await receivePort.first; String dataURL = "https://jsonplaceholder.typicode.com/posts"; /// 向其他线程发送消息 var msg = await sendReceive(sendPort,dataURL); setState(() { /// 更新UI,setState会触发build的执行 messages = msg; print(messages); });
  } static dataLoader(SendPort sendPort) async{ /// 其他线程的消息接收者 ReceivePort receivePort = new ReceivePort(); /// 通知其他isolate,当前isolate监听的端口 sendPort.send(receivePort.sendPort); await for(var msg in receivePort){ String data = msg[0]; // 获取URL SendPort replyTo = msg[1]; // 回传消息用的 String dataURL = data; /// 进行网络请求 Response response = await Dio().get(dataURL,options: Options(responseType: ResponseType.json),); /// 将结果回传回去 replyTo.send(response.data); }
  } /// 向其他线程发送消息
  Future sendReceive(SendPort port,msg){ /// 当前线程的接收者 ReceivePort receivePort =  new ReceivePort(); /// 向其他线程发送消息 port.send([msg,receivePort.sendPort]); return receivePort.first;
  }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

“dataLoader”是在它自己的独立执行线程中运行的隔离区,可以在其中执行CPU密集型任务,例如解析大于1万的JSON或执行计算密集型数学计算。

完整示例:

import 'dart:convert';
import 'dart:isolate';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

void main() => runApp(DemoApp());

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) { return new MaterialApp( title: '导航演示1', home: new MyAppHome(), );
  }
}

class MyAppHome extends StatefulWidget {
  @override
  MyAppHomeState createState() => MyAppHomeState();
}

class MyAppHomeState extends State<MyAppHome> { @override
  Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Hello"), ), body: Center( child: RaisedButton( child: Text("Go"), onPressed: () { loadData(); }, ), ), );
  } List messages;
  loadData() async { // 当前线程的信息的接收者 ReceivePort receivePort = new ReceivePort(); /** * 创建并生成与当前隔离共享相同代码的隔离。 * Isolate.spawn 接受的方法必须是静态的或是一个顶层函数 * 传递当前接收者receivePort.sendPort给其他线程,那么其他线程就可以通过它,与当前线程通信 * */ await Isolate.spawn(dataLoader, receivePort.sendPort); SendPort sendPort = await receivePort.first; String dataURL = "https://jsonplaceholder.typicode.com/posts"; /// 向其他线程发送消息 List msg = await sendReceive(sendPort,dataURL); setState(() { /// 更新UI,setState会触发build的执行 messages = msg; print(messages[0]["title"]); });
  } static dataLoader(SendPort sendPort) async{ /// 其他线程的消息接收者 ReceivePort receivePort = new ReceivePort(); /// 通知其他isolate,当前isolate监听的端口 sendPort.send(receivePort.sendPort); await for(var msg in receivePort){ String data = msg[0]; // 获取URL SendPort replyTo = msg[1]; // 回传消息用的 String dataURL = data; /// 进行网络请求 Response response = await Dio().get(dataURL); /// 将结果回传回去 replyTo.send(jsonDecode(response.toString())); }
  } /// 向其他线程发送消息
  Future sendReceive(SendPort port,msg){ /// 当前线程的接收者 ReceivePort receivePort =  new ReceivePort(); /// 向其他线程发送消息 port.send([msg,receivePort.sendPort]); return receivePort.first;
  }

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/108065712

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。