(轉載)flutter Isolate及compute使用

這篇文章將會講解flutter中的Isolate,這有助于幫你解決某些耗時計算問題導致的卡頓。

一 . 原始代碼

為什么要Isolate,我們先看一段比較簡單的代碼:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
 
class TestWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TestWidgetState();
  }
}
 
class TestWidgetState extends State<TestWidget> {
  int _count = 0;
 
  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Column(
          children: <Widget>[
            Container(
              width: 100,
              height: 100,
              child: CircularProgressIndicator(),
            ),
            FlatButton(
                onPressed: () async {
                  _count = countEven(1000000000);
                  setState(() {});
                },
                child: Text(
                  _count.toString(),
                )),
          ],
          mainAxisSize: MainAxisSize.min,
        ),
      ),
    );
  }

  //計算偶數(shù)的個數(shù)
  static int countEven(int num) {
    int count = 0;
    while (num > 0) {
      if (num % 2 == 0) {
        count++;
      }
      num--;
    }
    return count;
  }
}

UI包含兩個部分,一個不斷轉圈的progress指示器,一個按鈕,當點擊按鈕的時候,找出比某個正整數(shù)n小的數(shù)的偶數(shù)的個數(shù)(請忽視具體算法,故意做耗時計算用,哈哈)。我們來運行一下代碼看看效果:


image

可以看到,本來是很流暢的轉圈,當我點擊按鈕計算的時候,UI出現(xiàn)了卡頓,為什么會出現(xiàn)卡頓,因為我們的計算默認是在UI線程中的,當我們調用countEven的時候,這個計算需要耗時,而在這期間,UI是沒有機會去調用刷新的,因此會卡頓,計算完成后,UI恢復正常刷新。

二. 使用async優(yōu)化

那么有些同學就會說了,在dart中,有async關鍵字,我們可以用異步計算,這樣就不會影響UI的刷新了,事實真的是這樣嗎?我們一起來修改一下代碼:

a. 將count改為asyncCountEven

  static Future<int> asyncCountEven(int num) async{
    int count = 0;
    while (num > 0) {
      if (num % 2 == 0) {
        count++;
      }
      num--;
    }
    return count;
  }

b. 調用:

_count = await asyncCountEven(1000000000);

我們繼續(xù)運行一下代碼,看現(xiàn)象:


image

仍然卡頓,說明異步是解決不了問題的,為什么?因為我們仍舊是在同一個UI線程中做運算,異步只是說我可以先運行其他的,等我這邊有結果再返回,但是,記住,我們的計算仍舊是在這個UI線程,仍會阻塞UI的刷新,異步只是在同一個線程的并發(fā)操作。

三. 使用compute優(yōu)化

那么我們怎么解決這個問題呢,其實很簡單,我們知道卡頓的原因是在同一個線程中導致的,那我們有沒有辦法將計算移到新的線程中呢,當然是可以的。不過在dart中,這里不是稱呼線程,是Isolate,直譯叫做隔離,這么古怪的名字,是因為隔離不共享數(shù)據,每個隔離中的變量都是不同的,不能相互共享。

但是由于dart中的Isolate比較重量級,UI線程和Isolate中的數(shù)據的傳輸比較復雜,因此flutter為了簡化用戶代碼,在foundation庫中封裝了一個輕量級compute操作,我們先看看compute,然后再來看Isolate。

要使用compute,必須注意的有兩點,一是我們的compute中運行的函數(shù),必須是頂級函數(shù)或者是static函數(shù),二是compute傳參,只能傳遞一個參數(shù),返回值也只有一個,我們先看看本例中的compute優(yōu)化吧:

真的很簡單,只用在使用的時候,放到compute函數(shù)中就行了。

_count = await compute(countEven, 1000000000);

再次運行,我們來看看效果吧:


image

可以看到,現(xiàn)在的計算并不會導致UI卡頓,完美解決問題。

四. 使用Isolate優(yōu)化

但是,compute的使用還是有些限制,它沒有辦法多次返回結果,也沒有辦法持續(xù)性的傳值計算,每次調用,相當于新建一個隔離,如果調用過多的話反而會適得其反。在某些業(yè)務下,我們可以使用compute,但是在另外一些業(yè)務下,我們只能使用dart提供的Isolate了,我們先看看Isolate在本例中的使用:
a. 增加這兩個函數(shù)

  static Future<dynamic> isolateCountEven(int num) async {
    final response = ReceivePort();
    await Isolate.spawn(countEvent2, response.sendPort);
    final sendPort = await response.first;
    final answer = ReceivePort();
    sendPort.send([answer.sendPort, num]);
    return answer.first;
  }
 
  static void countEvent2(SendPort port) {
    final rPort = ReceivePort();
    port.send(rPort.sendPort);
    rPort.listen((message) {
      final send = message[0] as SendPort;
      final n = message[1] as int;
      send.send(countEven(n));
    });
  }

b. 使用

_count = await isolateCountEven(1000000000);

相對于compute復雜了很多,效果就不貼了,和compute一樣,毫無卡頓。。

五. 擴展
isolate使用這么復雜,那么我們在那些情況下使用它呢?

想象一下,假如你有一個業(yè)務,是使用socket和服務器連接,不斷的從服務器中讀取tcp流,如果業(yè)務需要拆分包的話,我們需要不斷的將讀取到的tcp流進行拆包分包,然后使用獲取的數(shù)據來更新UI。首先,我們的socket與服務器通信,如果服務器推送消息過快,那么肯定會出現(xiàn)上面的情況,socket這邊一直阻塞線程,導致UI刷新卡頓,所以我們需要將socket這邊的業(yè)務放到隔離里面,但是,compute函數(shù)的限制我們也說了,它基本是是一次運行一次返回,但是業(yè)務要求是通過tcp的長連接不斷獲取服務器的數(shù)據,所以,這里我們就只能使用isolate,在UI和isolate里面使用ReceivePort進行雙向通信,這樣才能保證UI不卡頓的情況下仍然保持業(yè)務的完整性。
————————————————
版權聲明:本文為CSDN博主「Hirabbit_jaden」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/email_jade/article/details/88941434

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容