本系列同步發表在 個人部落格,歡迎大家關注~
題外話
到昨天,本人就撐完此系列的一半了,可喜可賀~
不過在這資訊時代,難免會在意自己文章被別人閱讀的想法或次數,簡單來說就是流量
我是正式開賽後隔一個禮拜才開始發文,一開始覺得這主題(Mobile Development)好像沒太多人關注,好幾個參賽者跟我一樣,最多也才一、兩百瀏覽次數。
結果在 9/17 這主題的熱門文章突然間殺出一篇 5000+ 瀏覽次數的,
我當場直接
傻爆眼 ...
哇靠! 是一夜之間從哪裡烙這麼多人來點閱的... 莫非是哪位超級大神寫的文 !?
我花這麼長時間準備才寫出一篇 100+ 瀏覽次數,不免有些氣餒阿...
雖然知道 ithelp 有這方面的 Bug,但我看之前幾屆好像都沒這麼誇張...
後來在 9/20 這主題由 badgameshowtw 發出 [Day 4] Xcode安裝 為什麼有5000觀看??? ithelp觀察實驗 這篇文刷了十幾萬瀏覽後, ithelp 有人開始修正這問題。
好拉,這題外話算是有些抱怨,也希望評分沒有過度參考這數據。
當然期望 ithelp 有更好的機制,也勉勵其他跟我一樣的參賽者能堅持下去,為社群貢獻出優質文章囉~
好了,正篇開始
如果你看自己的 github.com 首頁,就會顯示所有的活動。
基本上活動頁就是此頁面的 App 版,研究之後應該是調用 GitHub REST API v3 - Feeds 這個 API。
不過我所使用的 github
套件似乎還沒整合這個 API;內容之後補上。
內容待補
如果一直沒人實現這部份,或許有時間我會發個 PR 給作者吧
接著我直接修改議題頁拉~
其實跟昨天的 [倉庫頁 - 改],差不多概念;一樣使用 FutureBuilder
、修改 issueList
、實現 fetchIssues()
函數。
lib/pages/issue.dart
...
@override
Widget build(BuildContext context) {
return Scrollbar(
child: RefreshIndicator(
child: FutureBuilder(
future: issueList,
builder: (BuildContext context, AsyncSnapshot<List<Issue>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
if (!snapshot.hasError) {
return ListView.separated(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
final now = DateTime.now();
final difference =
now.difference(snapshot.data[index].createdAt);
var createTimeAgo =
timeago.format(now.subtract(difference));
return ListTile(
dense: true,
leading: CircleAvatar(
radius: 18.0,
backgroundImage:
NetworkImage(snapshot.data[index].user.avatarUrl),
),
title: Text(snapshot.data[index].title),
subtitle: Text(createTimeAgo),
trailing: Icon(Icons.error_outline),
onTap: () {},
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 0.0),
);
} else {
return Center(child: Text("No Data"));
}
break;
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
}
},
),
onRefresh: () async {
await Future.delayed(Duration(seconds: 1));
setState(() {
issueList = fetchIssues();
});
},
),
);
}
Future<List<Issue>> fetchIssues() async {
return githubClient.issues.listAll(state: "all").toList();
}
對比昨天的程式碼是不是 87 分像阿~
小提醒:
- 在顯示議題創建時間上面,我使用了
timeago
這個套件,非常好用~- https://stackoverflow.com/questions/49340116/setstate-called-after-dispose
--
成果
大致改完所有首頁的內容後,我覺得應該來講一下 State
的生命週期。
說是「生命週期」,其實就是從(預備)創建畫面、顯示畫面、離開畫面,其中過程調用到的函數。
我直接找別人整理好的附圖,直接看右半邊的部份。
參考自 https://blog.duicode.com/3108.html
左半邊為 Android App 的生命週期。
可能大家可以看得出來繼承 StatefulWidget
的 Widget 在程式碼最大的特點,就是會重寫(override) createState()
這個函數。
從 createState()
開啟 State 的生命週期,而我個人最常用到的函數為 intState()
、build()
、 dispose()
和 setState()
。
State 物件有著以下的生命週期:
- 框架(Flutter)會藉由調用
StatefulWidget.createState
方法建造一個State
物件。- 每個新建出來的
State
物件會永久對應一個BuildContext
,但State
物件並不會改變BuildContext
。此時會將 State 物件標記成為 mounted(mounted=true
) 狀態。- 調用
initState
,可藉由重寫(override) initState 來初始化設定。- 調用
didChangeDependencies
。- 此時
State
物件已做好全面初始化,接下來調用build
方法來建構 UI。State
物件可藉由setState
方法來重建或調整 UI。- 在重建或調整 UI 的過程中,
State
物件會先調用didUpdateWidget
方法看有沒有對應的 Widget 需要作改變,didUpdateWidget
之後一定會再調用build
方法(意味著在didUpdateWidget
內用setState
是沒意義的)。- 在開發過程中,熱重載會調用
reassemble
方法。- 當
State
物件從 Tree 中被移除會調用deactivate
方法。- 如果
State
物件有插入至其他 Subtree 會調用build
方法,否則會調用dispose
方法。- 當調用
dispose
方法後,State
物件會被標記成 unmounted (mounted=false
),生命週期就此結束。不負責之簡易翻譯自 https://api.flutter.dev/flutter/widgets/State-class.html
--
小提醒:
- State 生命週期過程中其實有很多細節,礙於全部翻譯出來會很冗長,所以我只挑重點部份翻譯,詳細的話還是得要讀官方文件。
- 小弟也是讀了文件後才更深入的理解 "State"fulWidget 中的祕密。
小弟菜鳥,一開始還在想說為什麼 dart lint 一直噴出警示:
給其他一樣是菜鳥的讀者建議,
在 switch case 當中,還是要放個 default 時的 return 值。
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
default:
return Center(child: CircularProgressIndicator());
感謝作者文章,
因為個人學習方式習慣做中學,因此會挑選實作篇重的文章參考。
這系列看到這,長惹不少知識,感謝大大!
哈哈 能幫助到你是我的榮幸,感謝你給我的系列文肯定