Flutter Go 源碼分析(一)

前言

在經(jīng)過了一段時(shí)間的Flutter學(xué)習(xí)之后迹缀,感覺自己該來點(diǎn)項(xiàng)目實(shí)戰(zhàn)了曲横,在找了很多開源項(xiàng)目之后,最終決定學(xué)習(xí)阿里大佬們開發(fā)的Flutter Go項(xiàng)目,此文章以記錄自己的學(xué)習(xí)過程拧晕,感謝大佬們的無私開源,項(xiàng)目下載地址梅垄。

目錄

Flutter Go 學(xué)習(xí)之路(二)
Flutter Go 學(xué)習(xí)之路(三)
Flutter Go 學(xué)習(xí)之路(四)
Flutter Go 學(xué)習(xí)之路(五)
Flutter Go 學(xué)習(xí)之路(六)

我們從入口main()函數(shù)開始學(xué)起厂捞,先說明一些初始化的這幾個(gè)類:

void main() async {
  final provider = new Provider();
  await provider.init(true);//創(chuàng)建/打開 數(shù)據(jù)庫
  sp = await SpUtil.getInstance();//用來做shared_preferences的存儲(chǔ)
  new SearchHistoryList(sp);//工廠方法獲取實(shí)例對(duì)象  獲取本地搜索記錄列表 單例
  db = Provider.db;
  runApp(new MyApp());
}
(1) Provider

??它是對(duì)數(shù)據(jù)庫操作相關(guān)的類,用于創(chuàng)建數(shù)據(jù)庫的工具队丝,首先我們來看一下初始化方法:

//初始化數(shù)據(jù)庫
  Future init(bool isCreate) async {
    //Get a location using getDatabasesPath
    String databasesPath = await getDatabasesPath();// 獲取數(shù)據(jù)庫路徑 sqflite三方
    String path = join(databasesPath, 'flutter.db');//拼接App數(shù)據(jù)庫名稱
    print(path);
    try {//嘗試打開數(shù)據(jù)庫 如果已經(jīng)創(chuàng)建
      db = await openDatabase(path);
    } catch (e) {
      print("Error $e");
    }
    bool tableIsRight = await this.checkTableIsRight();//檢查數(shù)據(jù)庫中表是否完整

    if (!tableIsRight) {//如果不完整就刪除重新創(chuàng)建
      // 關(guān)閉上面打開的db靡馁,否則無法執(zhí)行open
      db.close();
      // Delete the database
      await deleteDatabase(path);
      ByteData data = await rootBundle.load(join("assets", "app.db"));//讀取assets app.db(創(chuàng)建表)的數(shù)據(jù)
      List<int> bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await new File(path).writeAsBytes(bytes);//將讀取的數(shù)據(jù)寫入路徑
  //打開數(shù)據(jù)庫
      db = await openDatabase(path, version: 1,
          onCreate: (Database db, int version) async {
        print('db created version is $version');
      }, onOpen: (Database db) async {
        print('new db opened');
      });
    } else {
      print("Opening existing database");
    }
  }

app.db表

??init方法總體實(shí)現(xiàn)思路就是

  • 1)先通過openDatabase(path);嘗試打開數(shù)據(jù)庫。
  • 2)再通過checkTableIsRight方法檢查數(shù)據(jù)庫是否存在或者完整:
// 檢查數(shù)據(jù)庫中, 表是否完整, 在部份android中, 會(huì)出現(xiàn)表丟失的情況
  Future checkTableIsRight() async {
    List<String> expectTables = ['cat', 'widget', 'collection'];

    List<String> tables = await getTables();

    for(int i = 0; i < expectTables.length; i++) {
      if (!tables.contains(expectTables[i])) {
        return false;
      }
    }
   return true;

  }
  • 3)如果沒有創(chuàng)建過或者表不完整就會(huì)刪除重新創(chuàng)建數(shù)據(jù)表await deleteDatabase(path);,在通過本地assets 下的app.db按表名寫入一個(gè)空的
ByteData data = await rootBundle.load(join("assets", "app.db"));
      List<int> bytes =
          data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await new File(path).writeAsBytes(bytes);

??最后打開數(shù)據(jù)庫机久。

(2) SpUtil

??這個(gè)是用來做本地化存儲(chǔ)的臭墨,主要代碼:

static SharedPreferences _spf;


  SpUtil._();

  Future _init() async {
    //SharedPreferences 數(shù)據(jù)本地化相關(guān)工具 NSUserDefaults (on iOS) and SharedPreferences (on Android)
    _spf = await SharedPreferences.getInstance();
  }

  static Future<SpUtil> getInstance() async  {
    if (_instance == null) {
      _instance = new SpUtil._();
      await _instance._init();

    }
    return _instance;
  }

這里我們看_spf實(shí)例是一個(gè)SharedPreferences,它就相當(dāng)于iOS的NSUserDefaults或者安卓的SharedPreferences.剩下的其他一些方法都是些寫入或者讀取的方法,這里就不過多闡述了膘盖。

(3) SearchHistoryList

?? SearchHistoryList是利用SpUtil用來存取搜索記錄的工具我們主要來看一下它的構(gòu)造方法:

static SpUtil _sp;
  static SearchHistoryList _instance;
  static List<SearchHistory> _searchHistoryList = [];

  static SearchHistoryList _getInstance(SpUtil sp) {
    if (_instance == null) {
      _sp = sp;
      String json = sp.get(SharedPreferencesKeys.searchHistory);
      _instance = new SearchHistoryList.fromJSON(json);//初始化方法
    }
    return _instance;
  }
  //工廠模式 實(shí)現(xiàn)
  factory SearchHistoryList([SpUtil sp]) {
    if (sp == null && _instance == null) {
      print(new ArgumentError(
          ['SearchHistoryList need instantiatied SpUtil at first timte ']));
    }
    return _getInstance(sp);
  }

//  List<SearchHistory> _searchHistoryList = [];

  // 存放的最大數(shù)量
  int _count = 10;

  SearchHistoryList.fromJSON(String jsonData) {
    _searchHistoryList = [];//存儲(chǔ)的是SearchHistory  model
    if (jsonData == null) {
      return;
    }
    List jsonList = json.decode(jsonData);
    jsonList.forEach((value) {
      _searchHistoryList.add(SearchHistory(
          name: value['name'], targetRouter: value['targetRouter']));
    });
  }

執(zhí)行順序是:factory SearchHistoryList([SpUtil sp])-->static SearchHistoryList _getInstance(SpUtil sp)-->SearchHistoryList.fromJSON(String jsonData)并且在初始化的時(shí)候搜索記錄列表就已經(jīng)取出存到了_searchHistoryList里面胧弛,其他的一些存取方法也不過多闡述。

(4) MyApp() 主程序框架
class MyApp extends StatelessWidget {
  MyApp()  {
    final router = new Router();

    Routes.configureRoutes(router);

    Application.router = router;
  }
  showWelcomePage() {
    // 暫時(shí)關(guān)掉歡迎介紹
    return AppPage();
//    bool showWelcome = sp.getBool(SharedPreferencesKeys.showWelcome);
//    if (showWelcome == null || showWelcome == true) {
//      return WelcomePage();
//    } else {
//      return AppPage();
//    }
  }
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'title',
      theme: new ThemeData(
        primaryColor: Color(ThemeColor),
        backgroundColor: Color(0xFFEFEFEF),
        accentColor: Color(0xFF888888),
        textTheme: TextTheme(
          //設(shè)置Material的默認(rèn)字體樣式
          body1: TextStyle(color: Color(0xFF888888), fontSize: 16.0),
        ),
        iconTheme: IconThemeData(
          color: Color(ThemeColor),
          size: 35.0,
        ),
      ),
      home: new Scaffold(
        body: showWelcomePage()
      ),
      onGenerateRoute: Application.router.generator,
      navigatorObservers: <NavigatorObserver>[Analytics.observer],
    );
  }
}

這里構(gòu)造方法里面進(jìn)行了Router的初始化和注冊(cè)侠畔,用到了fluro庫,具體用法大家自行去了解结缚,不再做闡述。
在flutter應(yīng)用中软棺,一般一個(gè)應(yīng)用都對(duì)應(yīng)一個(gè)MaterialApp這個(gè)組件是flutter應(yīng)用程序的骨架:

    this.navigatorKey, // 導(dǎo)航的key
    this.home, // 主頁
    this.routes = const <String, WidgetBuilder>{},// 路由
    this.initialRoute,//初始路由
    this.onGenerateRoute,//生成路由
    this.onUnknownRoute,//位置路由
    this.navigatorObservers = const <NavigatorObserver>[],//導(dǎo)航的觀察者
    this.builder,//widget的構(gòu)建
    this.title = '',//設(shè)備用于識(shí)別用戶的應(yīng)用程序的單行描述红竭。在Android上,標(biāo)題顯示在任務(wù)管理器的應(yīng)用程序快照上方喘落,當(dāng)用戶按下“最近的應(yīng)用程序”按鈕時(shí)會(huì)顯示這些快照茵宪。 在iOS上,無法使用此值瘦棋。 來自應(yīng)用程序的`Info.plist`的`CFBundleDisplayName`在任何時(shí)候都會(huì)被引用稀火,否則就會(huì)引用`CFBundleName`。要提供初始化的標(biāo)題兽狭,可以用 onGenerateTitle憾股。
    this.onGenerateTitle,//每次在WidgetsApp構(gòu)建時(shí)都會(huì)重新生成
    this.color,//背景顏色
    this.theme,//主題鹿蜀,用ThemeData
    this.locale,//app語言支持
    this.localizationsDelegates,//多語言代理
    this.localeResolutionCallback,//
    this.supportedLocales = const <Locale>[Locale('en', 'US')],//支持的多語言
    this.debugShowMaterialGrid = false,//顯示網(wǎng)格
    this.showPerformanceOverlay = false,//打開性能監(jiān)控箕慧,覆蓋在屏幕最上面
    this.checkerboardRasterCacheImages = false,
    this.checkerboardOffscreenLayers = false,
    this.showSemanticsDebugger = false,//打開一個(gè)覆蓋圖服球,顯示框架報(bào)告的可訪問性信息 顯示邊框
    this.debugShowCheckedModeBanner = true,//右上角顯示一個(gè)debug的圖標(biāo)

這里主要說一下onGenerateRoute: Application.router.generator,這句代碼,這里是配合fluro庫使用的颠焦,上面代碼也可以注釋掉:

home: new Scaffold(
        body: showWelcomePage()
      ),

然后再注冊(cè)的時(shí)候注冊(cè)一下"/"就好:

router.define("/", handler: homeHandler);
// app的首頁
var homeHandler = new Handler(
  handlerFunc: (BuildContext context, Map<String, List<String>> params) {
    return new AppPage();
  },
);

其余屬性自行去了解斩熊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伐庭,隨后出現(xiàn)的幾起案子粉渠,更是在濱河造成了極大的恐慌,老刑警劉巖圾另,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霸株,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡集乔,警方通過查閱死者的電腦和手機(jī)去件,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扰路,“玉大人尤溜,你說我怎么就攤上這事『钩” “怎么了宫莱?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)哩罪。 經(jīng)常有香客問我授霸,道長(zhǎng),這世上最難降的妖魔是什么际插? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任绝葡,我火速辦了婚禮,結(jié)果婚禮上腹鹉,老公的妹妹穿的比我還像新娘藏畅。我一直安慰自己,他們只是感情好功咒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布愉阎。 她就那樣靜靜地躺著,像睡著了一般力奋。 火紅的嫁衣襯著肌膚如雪榜旦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天景殷,我揣著相機(jī)與錄音溅呢,去河邊找鬼澡屡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛咐旧,可吹牛的內(nèi)容都是我干的驶鹉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铣墨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼室埋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伊约,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤姚淆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后屡律,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腌逢,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年超埋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了搏讶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纳本,死狀恐怖窍蓝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情繁成,我是刑警寧澤吓笙,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站巾腕,受9級(jí)特大地震影響面睛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尊搬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一叁鉴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧佛寿,春花似錦幌墓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至弹渔,卻和暖如春胳施,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肢专。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工舞肆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焦辅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓椿胯,卻偏偏與公主長(zhǎng)得像筷登,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子压状,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容