Flutter Future 詳解

語(yǔ)雀

什么是 Future

FutureDart中提供的一個(gè)抽象類(lèi)嚣镜、泛型類(lèi)约谈,它用于封裝一段在將來(lái)會(huì)被執(zhí)行的代碼邏輯城须。構(gòu)造一個(gè)Future就會(huì)向event queue中添加一條記錄律姨。如果把event queue類(lèi)比Android中的message queue的話(huà),那么可以簡(jiǎn)單的把Future類(lèi)比為Android中的Message.只不過(guò)Future中包含了需要完成的整個(gè)操作公般。并且利用Future的then和whenComplete方法可以指定在完成Future包含的操作后立馬執(zhí)行另一段邏輯万搔。 關(guān)于Future的更多詳情可以參閱官方文檔

繼續(xù)之前我感覺(jué)很有必要了解下Dart中的消息機(jī)制 9倭薄K脖ⅰ!刽虹!

Dart的消息循環(huán)機(jī)制

Dart的單線程執(zhí)行

當(dāng)一個(gè)Dart的方法開(kāi)始執(zhí)行時(shí)酗捌,他會(huì)一直執(zhí)行直至達(dá)到這個(gè)方法的退出點(diǎn)。換句話(huà)說(shuō)Dart的方法是不會(huì)被其他Dart代碼打斷的涌哲。

Note:一個(gè)Dart的命令行應(yīng)用可以通過(guò)創(chuàng)建isolates來(lái)達(dá)到并行運(yùn)行的目的胖缤。isolates之間不會(huì)共享內(nèi)存,它們就像幾個(gè)運(yùn)行在不同進(jìn)程中的app阀圾,中能通過(guò)傳遞message來(lái)進(jìn)行交流哪廓。出了明確指出運(yùn)行在額外的isolates或者workers中的代碼外,所有的應(yīng)用代碼都是運(yùn)行在應(yīng)用的main isolate中初烘。要了解更多相關(guān)內(nèi)容涡真,可以查看https://www.dartlang.org/arti...

正如下圖所示,當(dāng)一個(gè)Dart應(yīng)用開(kāi)始的標(biāo)志是它的main isolate執(zhí)行了main方法肾筐。當(dāng)main方法退出后哆料,main isolate的線程就會(huì)去逐一處理消息隊(duì)列中的消息。

image

isolate

Dart是基于單線程模型的語(yǔ)言吗铐。在Dart中有一個(gè)很重要的概念叫isolate东亦,它其實(shí)就是一個(gè)線程或者進(jìn)程的實(shí)現(xiàn),具體取決于Dart的實(shí)現(xiàn)抓歼。默認(rèn)情況下讥此,我們用Dart寫(xiě)的應(yīng)用都是運(yùn)行在****main isolate****中的(可以對(duì)應(yīng)理解為Android中的main thread)拢锹。當(dāng)然我們?cè)诒匾臅r(shí)候也可以通過(guò)isolate API創(chuàng)建新的isolate,多個(gè)isolate可以更好的利用多核CPU的特性來(lái)提高效率萄喳。但是要注意的是在Dart中isolate之間是無(wú)法直接共享內(nèi)存的卒稳,不同的isolate之間只能通過(guò)isolate API進(jìn)行通信因?yàn)?isolate 是單線程實(shí)體他巨,所以 isolate中的代碼是按順序執(zhí)行的充坑。關(guān)于isolate更多詳情可以參閱官方文檔

Dart的消息循環(huán)和消息隊(duì)列

一個(gè)Dart應(yīng)用有一個(gè)消息循環(huán)(event loop) 和兩個(gè)消息隊(duì)列(event queue 和 microtask queue)染突。

每個(gè)isolate都有單獨(dú)的event loop

event隊(duì)列包含所有外來(lái)的事件:I/O捻爷,mouse events,drawing events份企,timers也榄,isolate之間的message等。

microtask 隊(duì)列在Dart中是必要的司志,因?yàn)橛袝r(shí)候事件處理想要在稍后完成一些任務(wù)但又希望是在執(zhí)行下一個(gè)事件消息之前甜紫。

event隊(duì)列包含Dart和來(lái)自系統(tǒng)其它位置的事件。但microtask隊(duì)列只包含來(lái)自當(dāng)前isolate的內(nèi)部代碼骂远。

正如下面的流程圖囚霸,當(dāng)main方法退出后,event循環(huán)就開(kāi)始它的工作激才。首先它會(huì)以FIFO的順序執(zhí)行micro task拓型,當(dāng)所有micro task執(zhí)行完后它會(huì)從event 隊(duì)列中取事件并執(zhí)行。如此反復(fù)瘸恼,直到兩個(gè)隊(duì)列都為空劣挫。

[圖片上傳失敗...(image-da7b58-1590043915319)]

Dart 中的代碼執(zhí)行優(yōu)先級(jí)可以分為三個(gè)級(jí)別:

  1. 在 Main 中寫(xiě)代碼將最先執(zhí)行;
  2. 執(zhí)行完 Main 中的代碼钞脂,然后會(huì)檢查并執(zhí)行 Microtask Queue 中的任務(wù)揣云, 通常使用 scheduleMicrotask 將事件添加到 MicroTask Queue 中;
  3. 最后執(zhí)行 EventQueue 隊(duì)列中的代碼冰啃,通常使用 Future 向 EventQueue加入事件邓夕,也可以使用 async 和 await 向 EventQueue 加入事件。

總結(jié):Dart 中事件的執(zhí)行順序:Main > MicroTask > EventQueue阎毅。

異步任務(wù)調(diào)度

當(dāng)有代碼可以在后續(xù)任務(wù)執(zhí)行的時(shí)候焚刚,有兩種方式,通過(guò)dart:async這個(gè)Lib中的API即可:

  • 使用Future類(lèi)扇调,可以將任務(wù)加入到Event Queue的隊(duì)尾
  • 使用scheduleMicrotask函數(shù)矿咕,將任務(wù)加入到Microtask Queue隊(duì)尾

當(dāng)使用EventQueue時(shí),需要考慮清楚,盡量避免microtask queue過(guò)于龐大碳柱,否則會(huì)阻塞其他事件的處理

image

大概了解上的知識(shí)點(diǎn)后,繼續(xù)Future:

Future狀態(tài)

  • pending - 執(zhí)行中捡絮;
  • completed - 執(zhí)行結(jié)束,分兩種情況要么成功要么失斄汀福稳;

創(chuàng)建Future

常用的創(chuàng)建方法如下:

image.png

基本用法:

Future(FutureOr<T> computation())

Future 的構(gòu)造方法,創(chuàng)建一個(gè)基本的Future

var f1 = Future(() {
  print("1111");
});
print("2222");

//2222
//1111

打印順序是 2222-1111 這里準(zhǔn)尋了Dart事件執(zhí)行順序 Main > MicroTask > EventQueue。

Future.value([FutureOr<T> value])

創(chuàng)建一個(gè)指定返回值的Future

Future.value("Success").then((value) => (print('123$value')));

Future.delayed()

創(chuàng)建一個(gè)延遲執(zhí)行的 Future

//延遲三秒執(zhí)行
 Future.delayed(Duration(seconds: 3), () {
   print("future delayed");
 });

Future.foreach(Iterable elements, FutureOr action(T element))

根據(jù)某個(gè)集合瑞侮,創(chuàng)建一系列的Future的圆,并且會(huì)按順序執(zhí)行這些Future

Future.forEach([1,2,3], (item) {
    return Future.delayed(Duration(seconds: 2),() {
      print(item);
    });
});

//1
//2
//3

根據(jù)集合 1,2,3 創(chuàng)建三個(gè)延遲的Future,每?jī)擅雸?zhí)行一次. 一共6秒

Future<List<T>> wait<T>(Iterable<Future<T>> futures, {bool eagerError: false, void cleanUp(T successValue)})

用來(lái)等待多個(gè)future完成半火,并收集它們的結(jié)果. 結(jié)果有成功和失敗

var f1 = Future.delayed(Duration(seconds: 1),() => (1));
var f2 = Future.delayed(Duration(seconds: 2),() => (2));
var f3 = Future.delayed(Duration(seconds: 3),() => (3));
Future.wait([f1,f2,f3]).then((value) => print(value)).catchError(print);
//[1, 2, 3]

上面的代碼3個(gè)延遲的例子,三秒之后輸出 [1,2,3]. 和上面6秒的例子對(duì)比下, 一個(gè) 順序執(zhí)行多個(gè)future越妈,一個(gè)是異步執(zhí)行多個(gè)future

var f1 = Future.delayed(Duration(seconds: 1),() => (1));
var f2 = Future.delayed(Duration(seconds: 2),() => throw "erro2");
var f3 = Future.delayed(Duration(seconds: 3),() => throw "erro3");
Future.wait([f1,f2,f3]).then((value) => print(value)).catchError(print);

//erro2

上面代碼,延遲2和3,都拋出異常,會(huì)直接拋出異常

Future.any(futures)

返回的是第一個(gè)執(zhí)行完成的future的結(jié)果,不會(huì)管這個(gè)結(jié)果是正確的還是error的钮糖。

Future.doWhile()

類(lèi)似java中doWhile的用法梅掠,重復(fù)性地執(zhí)行某一個(gè)動(dòng)作,直到返回false或者Future藐鹤,退出循環(huán)瓤檐。

使用場(chǎng)景:適用于一些需要遞歸操作的場(chǎng)景。

Future.microtask(FutureOr computation())

創(chuàng)建一個(gè)在microtask隊(duì)列運(yùn)行的future娱节。

microtask隊(duì)列的優(yōu)先級(jí)是比event隊(duì)列高的,而一般future是在event隊(duì)列執(zhí)行的祭示,所以Future.microtask創(chuàng)建的future會(huì)優(yōu)先于其他future進(jìn)行執(zhí)行肄满。

Future(() => (print(11111)));
Future(() => (print(22222)));
Future.microtask(() => (print(33333)));

//flutter: 33333
//flutter: 11111
//flutter: 22222

處理Future結(jié)果

Flutter提供了下面三個(gè)方法,讓我們來(lái)注冊(cè)回調(diào)质涛,來(lái)監(jiān)聽(tīng)處理Future的結(jié)果稠歉。

//處理完成時(shí)候的回調(diào),一般都是成功回調(diào)
Future<R> then<R>(FutureOr<R> onValue(T value), {Function onError});
//處理失敗的回調(diào),比如throw一個(gè)error就會(huì)走到這里
Future<T> catchError(Function onError, {bool test(Object error)});
//Future.whenComplete總是在Future完成后調(diào)用,不管Future的結(jié)果是正確的還是錯(cuò)誤的汇陆。
Future<T> whenComplete(FutureOr action());

結(jié)合 async 和 await

Dart中他倆就是兄弟,一般都是一起出現(xiàn)的,來(lái)完成一個(gè)異步操作.

注意:await只能在async函數(shù)出現(xiàn)怒炸。 async函數(shù),返回值是一個(gè)Future對(duì)象毡代,如果沒(méi)有返回Future對(duì)象阅羹,會(huì)自動(dòng)將返回值包裝成Future對(duì)象。 捕捉錯(cuò)誤教寂,一般是使用try/catch機(jī)制來(lái)做異常處理捏鱼。 await 一個(gè)future,可以拿到Future的結(jié)果酪耕,直到拿到結(jié)果导梆,才執(zhí)行下一步的代碼。

void main() {
  print('t1:' + DateTime.now().toString());
  getData();
  print('t2:' + DateTime.now().toString());

}

getData() async {
    int result = await Future.delayed(Duration(milliseconds: 2000), () {
      return Future.value(123);
    });
    print('t3:' + DateTime.now().toString());
    print(result);
}

看上面的代碼,getData方法中,定義了一個(gè)延遲操作,執(zhí)行順序按照dart事件執(zhí)行順序是 t1-t2-t3-123,運(yùn)行代碼能看到猜想是對(duì)的.

try {
  var result1 = await Future.value(1);
  print(result1);//輸出1
  var result2 = await Future.value(2);
  print(result2);//輸出2
} catch (e) {
    //捕捉錯(cuò)誤
} finally {
  
}

上面的代碼和java一樣,利用try-catch-finally捕獲錯(cuò)誤

執(zhí)行順序

Dart的事件順序應(yīng)該都明白了,加深下印象

void test1(){
  Future f2 = Future(() => null);
  Future f1 = Future(() => null);
  Future f3 = Future(() => null);
  f1.then((_) => print("1"));
  f2.then((_) => print("2"));
  f3.then((_) => print("3"));
}

結(jié)果:

flutter: 2

flutter: 1

flutter: 3

有疑問(wèn)嗎,應(yīng)該沒(méi)有疑問(wèn),因?yàn)閒2是先初始化的.所以先執(zhí)行的f2】茨幔可見(jiàn) 創(chuàng)建多個(gè)Future递鹉,執(zhí)行順序和和創(chuàng)建Future的先后順序有關(guān).和調(diào)用then的先后順序無(wú)關(guān)

void test2() {
  Future f1 = Future(() => null);
  Future f2 = Future(() => null);
  Future f3 = Future(() => null);

  f1.then((_) => print("f1 -> f1"));
  f3.then((_) {
    print("f3 -> f3");
    f1.then((_) => print("f3.then -> f1"));
  });
  f2.then((_) => print("f2 -> f2"));
}

結(jié)果:

flutter: f1 -> f1
flutter: f2 -> f2
flutter: f3 -> f3
flutter: f3.then -> f1

上面也是按照創(chuàng)建順序執(zhí)行的.

import 'dart:async';
main() {
  print('main #1 of 2');
  scheduleMicrotask(() => print('microtask #1 of 2'));

  new Future.delayed(new Duration(seconds:1),
                     () => print('future #1 (delayed)'));
  new Future(() => print('future #2 of 3'));
  new Future(() => print('future #3 of 3'));

  scheduleMicrotask(() => print('microtask #2 of 2'));

  print('main #2 of 2');
}


結(jié)果:

flutter: main #1 of 2
flutter: main #2 of 2
flutter: microtask #1 of 2
flutter: microtask #2 of 2
flutter: future #2 of 3
flutter: future #3 of 3
flutter: future #1 (delayed)

上面代碼的執(zhí)行順序,是完全按照 Dart事件順序去執(zhí)行的.

  1. main()方法
  2. microtask隊(duì)列
  3. event隊(duì)列.

main方法中的普通代碼都是同步執(zhí)行的,所以肯定是main打印先全部打印出來(lái)藏斩,等main方法結(jié)束后會(huì)開(kāi)始檢查microtask中是否有任務(wù)梳虽,若有則執(zhí)行,執(zhí)行完繼續(xù)檢查microtask灾茁,直到microtask列隊(duì)為空窜觉。所以接著打印的應(yīng)該是microtask的打印。最后會(huì)去執(zhí)行event隊(duì)列北专。由于有一個(gè)使用的delay方法禀挫,所以它的打印應(yīng)該是在最后的。

void main() {

  print('main 1');
  scheduleMicrotask(() => print('microtask 1'));

  new Future.delayed(new Duration(seconds:1),
          () => print('future 1'));

  new Future(() => print('future 2'))
      .then((_) => print('future #2.1'))
      .then((_) {
    print('future #2.2');
    scheduleMicrotask(() => print('microtask 4'));
  })
      .then((_) => print('future #2.3'));

  scheduleMicrotask(() => print('microtask 2'));

  new Future(() => print('future 3'))
      .then((_) => new Future(
          () => print('future #3.1 new')))
      .then((_) => print('future #3.2'));

  new Future(() => print('future 4'));
  scheduleMicrotask(() => print('microtask 3'));
  print('main 2');

}

執(zhí)行結(jié)果:
flutter: main 1
flutter: main 2
flutter: microtask 1
flutter: microtask 2
flutter: microtask 3
flutter: future 2
flutter: future #2.1
flutter: future #2.2
flutter: future #2.3
flutter: microtask 4
flutter: future 3
flutter: future 4
flutter: future #3.1 new
flutter: future #3.2
flutter: future 1

有點(diǎn)多,看著有點(diǎn)繞,我們來(lái)試著梳理一下:

  1. 首先執(zhí)行兩個(gè)main 1 和 main2 這個(gè)沒(méi)有任何問(wèn)題
  2. 繼續(xù)執(zhí)行 microtask1,2,3 這個(gè)也沒(méi)有問(wèn)題, 現(xiàn)在是 man1,2 microtask 1,2,3
  3. 走到delayed,現(xiàn)在應(yīng)該是 : man1,2 microtask 1,2,3 ... ... f1
  4. 繼續(xù)走,走到了f2拓颓,現(xiàn)在應(yīng)該是 : man1,2 microtask 1,2,3语婴,f2, ... ... f1
  5. 因?yàn)閒2中有3個(gè)then,所以現(xiàn)在應(yīng)該是 : man1,2 microtask 1,2,3,f2, f2.1, f2.2, f2.3 ... ... f1
  6. 到這里應(yīng)該沒(méi)有疑問(wèn)吧. 有人說(shuō)f2.2中有mic4驶睦,為啥不走他呢,因?yàn)楦瓌t mic4會(huì)在 f2執(zhí)行完畢之后執(zhí)行,所以現(xiàn)在應(yīng)該是 : man1,2 microtask 1,2,3砰左,f2, f2.1, f2.2, f2.3, mic4, ... ... f1
  7. 繼續(xù)走到f3 ,會(huì)輸出f3场航,但是在then中新建了一個(gè)future,所以他會(huì)放到event隊(duì)列的最后執(zhí)行,所以這個(gè)時(shí)候應(yīng)該是 輸出: man1,2 microtask 1,2,3缠导,f2, f2.1, f2.2, f2.3, mic4,f3 ... ... f3.1, f3.2, f1
  8. 繼續(xù)走到了的 f4, 整個(gè)也就執(zhí)行結(jié)束了.最后的結(jié)果是 : man1,2 microtask 1,2,3溉痢,f2, f2.1, f2.2, f2.3, mic4,f3 ,f4 ,f3.1, f3.2, f1

看是上面的,我們知道Dart中,的事件順序是 main->microtask->event僻造,如果中間穿插,也是規(guī)則的總結(jié)如下:

  1. Future 的執(zhí)行順序?yàn)镕uture的在 EventQueue 的排列順序(****main->****microtask->event****)
  2. 當(dāng)任務(wù)需要延遲執(zhí)行時(shí),可以使用 new Future.delay() 來(lái)將任務(wù)延遲執(zhí)行孩饼。
  3. Future 如果執(zhí)行完才添加 than 髓削,該任務(wù)會(huì)被放入 microTask,當(dāng)前 Future 執(zhí)行完會(huì)執(zhí)行 microTask镀娶,microTask 為空后才會(huì)執(zhí)行下一個(gè)Future立膛。(上面的第6步)
  4. Future 是鏈?zhǔn)秸{(diào)用,意味著Future 的 then 未執(zhí)行完梯码,下一個(gè)then 不會(huì)執(zhí)行宝泵。

重要要在腦海里有一個(gè) EventQueue 的隊(duì)列模型,牢記先進(jìn)先出忍些。

FutureBuilder

FutureBuilder是一個(gè)將異步操作和異步UI更新結(jié)合在一起的類(lèi)鲁猩,通過(guò)它我們可以將網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)庫(kù)讀取等的結(jié)果更新的頁(yè)面上罢坝。

構(gòu)造方法:

const FutureBuilder({
    Key key,
    this.future,           //Future對(duì)象表示此構(gòu)建器當(dāng)前連接的異步計(jì)算廓握;
    this.initialData,      //表示一個(gè)非空的Future完成前的初始化數(shù)據(jù)搅窿;
    @required this.builder,// AsyncWidgetBuilder類(lèi)型的回到函數(shù),是一個(gè)基于異步交互構(gòu)建widget的函數(shù)隙券;
  }) 

這個(gè)builder函數(shù)接受兩個(gè)參數(shù)BuildContext contextAsyncSnapshot<T> snapshot男应,它返回一個(gè)widget。AsyncSnapshot包含異步計(jì)算的信息娱仔,它具有以下屬性:

connectionState - 枚舉ConnectionState的值沐飘,表示與異步計(jì)算的連接狀態(tài),ConnectionState有四個(gè)值:none牲迫,waiting耐朴,active和done;

data - 異步計(jì)算接收的最新數(shù)據(jù);

error - 異步計(jì)算接收的最新錯(cuò)誤對(duì)象盹憎;

AsyncSnapshot還具有hasDatahasError屬性筛峭,以分別檢查它是否包含非空數(shù)據(jù)值或錯(cuò)誤值。

例子

官方demo

FutureBuilder<String>(
  future: _calculation, // a previously-obtained Future<String> or null
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none:
        return Text('Press button to start.');
      case ConnectionState.active:
      case ConnectionState.waiting:
        return Text('Awaiting result...');
      case ConnectionState.done:
        if (snapshot.hasError)
          return Text('Error: ${snapshot.error}');
        return Text('Result: ${snapshot.data}');
    }
    return null; // unreachable
  },
)

可以看到 FutureBuilder 定義了一個(gè)泛型陪每,這個(gè)泛型是用來(lái)獲取快照中數(shù)據(jù)時(shí)用的影晓。

我們?cè)賮?lái)看一下 snapshot.connectionState 都有哪些值:

<colgroup><col span="1" width="360"><col span="1" width="360"></colgroup>

ConnectionState 當(dāng)前沒(méi)有連接到任何的異步任務(wù)
ConnectionState.none 當(dāng)前沒(méi)有連接到任何的異步任務(wù)
ConnectionState.waiting 連接到異步任務(wù)并等待進(jìn)行交互
ConnectionState.active 連接到異步任務(wù)并開(kāi)始交互
ConnectionState.done 異步任務(wù)中止

現(xiàn)在了解了之后我們?cè)诖蜷_(kāi)一個(gè)頁(yè)面的時(shí)候肯定會(huì)有網(wǎng)絡(luò)請(qǐng)求,這個(gè)時(shí)候要顯示 loading 之類(lèi)的檩禾,我們就可以利用當(dāng)前快照的狀態(tài)來(lái)返回不同的 widget

首先看build代碼:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('FutureBuilderPage'),
    ),
    body: FutureBuilder(
      builder: (context, snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.active:
          case ConnectionState.waiting:
            print('waiting');
            return Center(child: CupertinoActivityIndicator());
          case ConnectionState.done:
            print('done');
            if (snapshot.hasError) {
              return Center(
                child: Text('網(wǎng)絡(luò)請(qǐng)求出錯(cuò)'),
              );
            }
            return generateListView();
        }
        return null;
      },
      future: _future,
    ),
  );
}

Scaffold 的 body 直接返回一個(gè) FutureBuilder挂签,根據(jù)不同狀態(tài)來(lái)返回了不同的 widget。

這里需要注意的一點(diǎn)是:我們知道 StatefulWidget會(huì)長(zhǎng)時(shí)間維護(hù)一個(gè) State盼产,當(dāng)有變動(dòng)的時(shí)候會(huì)調(diào)用 didUpdateWidget 方法饵婆,就要重新build了。所以 FutureBuilder 的官方文檔上有這么一段文字:

The future must have been obtained earlier, e.g. during State.initState, State.didUpdateConfig , or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.buildmethod call when constructing the FutureBuilder. If the future is created at the same time as the FutureBuilder, then every time the FutureBuilder's parent is rebuilt, the asynchronous task will be restarted.A general guideline is to assume that every build method could get called every frame, and to treat omitted calls as an optimization.

大致意思就是說(shuō) future 這個(gè)參數(shù)建議在 initState() 里初始化辆飘,不要在 build 方法里初始化啦辐,這樣的話(huà)會(huì)一直 rebuild。

為什么呢蜈项,我們查看 didUpdateWidget 源碼:

@override
void didUpdateWidget(FutureBuilder<T> oldWidget) {
  super.didUpdateWidget(oldWidget);
  if (oldWidget.future != widget.future) {
    if (_activeCallbackIdentity != null) {
      _unsubscribe();
      _snapshot = _snapshot.inState(ConnectionState.none);
    }
    _subscribe();
  }
}

可以看出來(lái)這里是判斷了 future 這個(gè)字段, 所以我們一定不要在 build 方法里初始化 future 參數(shù)续挟!

所以紧卒,我們?cè)?initState()方法里初始化:

Future _future;
Dio _dio;
int date = 20190523;
List<Stories> _newsData = [];
@override
void initState() {
  super.initState();
  _dio = Dio();
  _future = getNewsList();
}
// 獲取知乎每天的新聞,數(shù)據(jù)獲取成功后 setState來(lái)刷新數(shù)據(jù)
Future getNewsList() async {
  var response =
    await _dio.get('https://news-at.zhihu.com/api/4/news/before/$date');
  setState(() {
    _newsData.addAll(ZhiHuNews.fromJson(response.data)._stories);
  });
}

FutureBuiler先說(shuō)這點(diǎn),以后大量使用后再做詳細(xì)記錄 ~

參考:

https://segmentfault.com/a/1190000008800122

http://www.reibang.com/p/c0e30769ea7e

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诗祸,一起剝皮案震驚了整個(gè)濱河市跑芳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌直颅,老刑警劉巖博个,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異功偿,居然都是意外死亡盆佣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)共耍,“玉大人虑灰,你說(shuō)我怎么就攤上這事”远担” “怎么了穆咐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)字旭。 經(jīng)常有香客問(wèn)我对湃,道長(zhǎng),這世上最難降的妖魔是什么遗淳? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任拍柒,我火速辦了婚禮,結(jié)果婚禮上洲脂,老公的妹妹穿的比我還像新娘斤儿。我一直安慰自己,他們只是感情好恐锦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布往果。 她就那樣靜靜地躺著,像睡著了一般一铅。 火紅的嫁衣襯著肌膚如雪陕贮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天潘飘,我揣著相機(jī)與錄音肮之,去河邊找鬼。 笑死卜录,一個(gè)胖子當(dāng)著我的面吹牛戈擒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播艰毒,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼筐高,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了丑瞧?” 一聲冷哼從身側(cè)響起柑土,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绊汹,沒(méi)想到半個(gè)月后稽屏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡西乖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年狐榔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坛增。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡荒叼,死狀恐怖轿偎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情被廓,我是刑警寧澤坏晦,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站嫁乘,受9級(jí)特大地震影響昆婿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜓斧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一仓蛆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挎春,春花似錦看疙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至脚线,卻和暖如春搁胆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背邮绿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工渠旁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人船逮。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓顾腊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挖胃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子投慈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353