天天看点

flutter实现异步UI

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);
            }
}      

要更新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);
            }
}      

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

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

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

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

完整示例:

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;
  }

}