從0開始設(shè)計Flutter獨立APP | 第一篇: 數(shù)據(jù)庫與狀態(tài)管理

鑒于Flutter高性能渲染和跨平臺的優(yōu)勢,閃點清單在移動端APP上,使用了完整的Flutter框架來開發(fā)竞穷。既然是完整APP,架構(gòu)搭建完全不受歷史Native APP的影響鳞溉,沒有歷史包袱的沉淀瘾带,設(shè)計也能更靈活和健壯。

Flutter

首先列舉部分閃點清單的業(yè)務(wù)特性(較為通用的業(yè)務(wù)特性):

  1. 本地有較大數(shù)據(jù)量的清單數(shù)據(jù)熟菲,離線可用看政,未登錄可用朴恳;登錄后需要服務(wù)器數(shù)據(jù)同步
  2. 狀態(tài)變更場景多,前端狀態(tài)邏輯較為復(fù)雜允蚣,跨頁面于颖、跨組件狀態(tài)更新頻繁

這幾個業(yè)務(wù)點,設(shè)計到的技術(shù)選型有:本地數(shù)據(jù)庫嚷兔、前端狀態(tài)管理森渐,對很多業(yè)務(wù)來說,這幾點都是比較核心的東西冒晰,也是我們今天重點要講的內(nèi)容同衣。

數(shù)據(jù)庫選型

數(shù)據(jù)庫選型,首先要定的壶运,就是選擇數(shù)據(jù)庫類型:關(guān)系型數(shù)據(jù)庫耐齐、非關(guān)系型數(shù)據(jù)庫還是Key/Value存儲。

對于關(guān)系型數(shù)據(jù)庫前弯,可選的有比如:SQLite蚪缀、Core Data、GreenDao等恕出;對于非關(guān)系型數(shù)據(jù)庫询枚,可選有Realm、UnQLite等浙巫;對于Key/Value存儲金蜀,有比如Redis、Berkeley DB的畴、Level DB等渊抄。

由于業(yè)務(wù)形態(tài)具有復(fù)雜的查詢場景,所以首先排除了Key/Value存儲丧裁;然后鑒于業(yè)務(wù)迭代頻繁护桦,數(shù)據(jù)結(jié)構(gòu)變動較大,所以完全的關(guān)系型數(shù)據(jù)庫使用成本會較高煎娇,版本更新時在數(shù)據(jù)兼容和數(shù)據(jù)清洗方面要做較多的工作二庵;所以我們采用了NoSQL數(shù)據(jù)庫,或者支持JSON類型的關(guān)系型數(shù)據(jù)庫缓呛。

Flutter目前在NoSQL上的可選項并不多催享,Realm、UnQLite等均未支持(當(dāng)然可以通過Flutter FFI來封裝給Dart用哟绊,但成本過高)因妙;Flutter的sqflite插件可以較好地支持SQLite,但由于SQLite在3.9以后才支持JSON數(shù)據(jù),考慮到Android版本(Android各版本使用的SQLite版本文檔)兼容問題攀涵,我們并沒有采用sqflite铣耘;我們最終采用的數(shù)據(jù)庫是Sembast,一個還比較小眾汁果,但性能和API建設(shè)都還不錯的NoSQL數(shù)據(jù)庫涡拘。

Flutter

Sembast介紹

Sembast API很簡潔,但能支持較復(fù)雜的數(shù)據(jù)庫操作据德。
在數(shù)據(jù)查詢上,能夠通過簡單的邏輯API跷车,通過聚合構(gòu)造出復(fù)雜的邏輯查詢語句棘利;數(shù)據(jù)排序?qū)崿F(xiàn)也比較完整,支持多字段排序(但不支持bool類型排序)朽缴;對事務(wù)操作也有支持善玫;支持整型自增key。

Sembast部分API預(yù)覽

var store = intMapStoreFactory.store('animals');

// 事務(wù)處理
await db.transaction((txn) async {
  await store.add(txn, {'name': 'fish'});
  await store.add(txn, {'name': 'cat'});
  await store.add(txn, {'name': 'dog'});
});

// 數(shù)據(jù)查詢
var finder = Finder(
    filter: Filter.greaterThan('name', 'cat'),
    sortOrders: [SortOrder('name')]);
var records = await store.find(db, finder: finder);

expect(records.length, 2);
expect(records[0]['name'], 'dog');
expect(records[1]['name'], 'fish');

但由于對小眾數(shù)據(jù)庫前途的擔(dān)憂考慮密强,我們設(shè)計了便于遷移的數(shù)據(jù)架構(gòu)茅郎,對數(shù)據(jù)操作層做了一層抽象,后期如果遷移數(shù)據(jù)庫或渤,業(yè)務(wù)層可以完全不需要改動系冗。

狀態(tài)管理選型

狀態(tài)管理,在如今的前端技術(shù)中薪鹦,是非常重要的一環(huán)掌敬,好的狀態(tài)管理框架,可以讓業(yè)務(wù)更好得解耦池磁、簡化組件數(shù)據(jù)通訊成本奔害、大幅提升開發(fā)體驗。我們在狀態(tài)管理選型上花了較多的時間來對比各種方案地熄,比如:provider华临、blocredux端考、scoped_model雅潭、mobx、甚至業(yè)界網(wǎng)紅團(tuán)隊的fish-redux跛梗。我們最終采用的是mobx寻馏,關(guān)于各個方案的對比,一篇文章講不完核偿,我們最終選擇mobx诚欠,更多是因為它的API更友好。

Mobx采用注解的方式來定義狀態(tài),并封裝了一個Widget用于Widget的數(shù)據(jù)更新轰绵,學(xué)習(xí)粉寞、使用成本較低。

Tech

注解定義

Mobx的注解使用方式左腔,與Web中的Vue非常類似如:

  1. 使用@observable來注解一個屬性唧垦,表示其需要被監(jiān)聽,Mobx會自動為其添加getter和setter
  2. 使用@computed來注解一個計算屬性
  3. 使用@action來注解一個修改store的方法液样,類似于Vuex里的mutations

示例代碼:

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @computed
  int get allowCount {
    return value*2;
  }

  @action
  void increment() {
    value++;
  }
}

使用Mobx必須的一個步驟振亮,就是前置編譯步驟。我們編寫Mobx的狀態(tài)腳本鞭莽,需要在前置編譯環(huán)節(jié)坊秸,編譯成dart可讀的腳本,為此我們需要執(zhí)行flutter pub run build_runner build生成.g.dart為后綴的文件(其實就是將注解轉(zhuǎn)義為getter和setter)澎怒。
UI更新方式

UI更新方式

需要使用Mobx的Widget褒搔,使用Observer包裝一層,這樣其就可以相應(yīng)Mobx的狀態(tài)變化喷面,如:

Observer(
  builder: (context) => Text('昵稱: ${userStore.user.username}'),
)

前置編譯腳本

Dart在編譯時和運(yùn)行時均無法支持注解星瘾,所以Mobx使用了前置編譯腳本解析注解動態(tài)生成Dart代碼的方式(Dart官方支持)。Mobx注解方式使用前惧辈,需要為項目添加build_runnermobx_codegen依賴琳状。build_runner為Dart官方提供,用于在構(gòu)建項目之前執(zhí)行特定任務(wù)咬像,任務(wù)配置于依賴庫的build.yaml腳本中; mobx_codegen依賴于該build_runner將注解生成可執(zhí)行的Dart代碼(如添加getter和setter方法)算撮。

結(jié)尾

狀態(tài)管理和數(shù)據(jù)庫,是前端項目基礎(chǔ)框架的重要環(huán)節(jié)县昂,設(shè)計好了可以很好地提升開發(fā)體驗和效率肮柜,降低后續(xù)開發(fā)維護(hù)成本。

講到這里倒彰,還并沒有完成基礎(chǔ)框架的搭建审洞,后面我們會講解更多的Flutter架構(gòu)設(shè)計內(nèi)容,比如:國際化待讳、通知芒澜、分享、UI設(shè)計等等创淡。


持續(xù)分享閃點清單在Flutter上的開發(fā)經(jīng)驗痴晦,閃點清單移動端APP體驗:

硬廣,很硬

閃點清單PC端APP: 業(yè)界唯一一款懸浮清單軟件

image

閃點清單移動端APP:

image

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琳彩,一起剝皮案震驚了整個濱河市誊酌,隨后出現(xiàn)的幾起案子部凑,更是在濱河造成了極大的恐慌,老刑警劉巖碧浊,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涂邀,死亡現(xiàn)場離奇詭異,居然都是意外死亡箱锐,警方通過查閱死者的電腦和手機(jī)比勉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驹止,“玉大人浩聋,你說我怎么就攤上這事‰担” “怎么了赡勘?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捞镰。 經(jīng)常有香客問我,道長毙替,這世上最難降的妖魔是什么岸售? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮厂画,結(jié)果婚禮上凸丸,老公的妹妹穿的比我還像新娘。我一直安慰自己袱院,他們只是感情好屎慢,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忽洛,像睡著了一般腻惠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上欲虚,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天集灌,我揣著相機(jī)與錄音,去河邊找鬼复哆。 笑死欣喧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的梯找。 我是一名探鬼主播唆阿,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锈锤!你這毒婦竟也來了驯鳖?” 一聲冷哼從身側(cè)響起闲询,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臼隔,沒想到半個月后嘹裂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡摔握,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年寄狼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氨淌。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡泊愧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盛正,到底是詐尸還是另有隱情删咱,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布豪筝,位于F島的核電站痰滋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏续崖。R本人自食惡果不足惜敲街,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望严望。 院中可真熱鬧多艇,春花似錦、人聲如沸像吻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拨匆。三九已至姆涩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涮雷,已是汗流浹背阵面。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留洪鸭,地道東北人样刷。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像览爵,于是被迫代替她去往敵國和親置鼻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355