redux_persist_flutter

在移動(dòng)端的開發(fā)中我們?nèi)绾潍@取用戶是否登錄呢,一般我們最常用的做法是在用戶登錄后將獲取的token存在本地然后在用戶下次登錄的時(shí)候我們從本地讀取這個(gè)token如果有那么我們判斷用戶之前登錄過,如果沒有我們就知道用戶沒有登錄.但是在接觸了redux以后發(fā)現(xiàn)redux有自己的數(shù)據(jù)持久化Redux Persist.那今天簡(jiǎn)單研究一下我們?nèi)绾问褂肦edux Persist進(jìn)行狀態(tài)的管理

首先我們就是想儲(chǔ)存一些我們已經(jīng)獲取的數(shù)據(jù)這個(gè)時(shí)候redux_persist_flutter給我們提供了一個(gè)關(guān)鍵的類Persistor,那我們點(diǎn)進(jìn)去看看這個(gè)Persistor到底是個(gè)什么

class Persistor<T> {
  /// Storage engine to save/load from/to.
  final StorageEngine storage;

  /// Transformations on state to be applied on save/load.
  final Transforms<T> transforms;

  /// Transformations on raw data to be applied on save/load.
  final RawTransforms rawTransforms;

  /// State serialized used to serialize the state to/from bytes.
  final StateSerializer<T> serializer;

  /// Debug mode (prints debug information).
  bool debug;

  /// Duration for which to throttle saving. Disable by setting to null.
  /// It is recommended to set a duration of a few (2-5) seconds to reduce
  /// storage calls, while preventing data loss.
  /// A duration of zero (default) will try to save on next available cycle
  Duration throttleDuration;

  /// Synchronization lock for saving
  final _saveLock = Lock();

  /// Function that if not null, returns if an action should trigger a save.
  final bool Function(Store<T> store, dynamic action) shouldSave;

  Persistor({
    @required this.storage,
    @required this.serializer,
    this.transforms,
    this.rawTransforms,
    this.debug = false,
    this.throttleDuration = Duration.zero,
    this.shouldSave,
  });

  /// Middleware used for Redux which saves on each action.
  Middleware<T> createMiddleware() {
    Timer _saveTimer;

    return (Store<T> store, dynamic action, NextDispatcher next) {
      next(action);

      if (shouldSave != null && shouldSave(store, action) != true) {
        return;
      }

      // Save
      try {
        if (throttleDuration != null) {
          // Only create a new timer if the last one hasn't been run.
          if (_saveTimer?.isActive != true) {
            _saveTimer = Timer(throttleDuration, () => save(store.state));
          }
        } else {
          save(store.state);
        }
      } catch (_) {}
    };
  }

  /// Load state from storage
  Future<T> load() async {
    try {
      _printDebug('Starting load...');

      _printDebug('Loading from storage');

      // Load from storage
      Uint8List data;
      try {
        data = await storage.load();
      } catch (error) {
        throw StorageException('On load: ${error.toString()}');
      }

      _printDebug('Running load raw transformations');

      try {
        // Run all raw load transforms
        rawTransforms?.onLoad?.forEach((transform) {
          data = transform(data);
        });
      } catch (error) {
        throw TransformationException(
          'On load raw transformation: ${error.toString()}',
        );
      }

      _printDebug('Deserializing');

      T state;
      try {
        state = serializer.decode(data);
      } catch (error) {
        throw SerializationException('On load: ${error.toString()}');
      }

      _printDebug('Running load transformations');

      try {
        // Run all load transforms
        transforms?.onLoad?.forEach((transform) {
          state = transform(state);
        });
      } catch (error) {
        throw TransformationException(
          'On load transformation: ${error.toString()}',
        );
      }

      _printDebug('Done loading!');

      return state;
    } catch (error) {
      _printDebug('Error while loading: ${error.toString()}');
      rethrow;
    }
  }

  /// Save state to storage.
  Future<void> save(T state) async {
    try {
      _printDebug('Starting save...');

      _printDebug('Running save transformations');

      // Run all save transforms
      try {
        transforms?.onSave?.forEach((transform) {
          state = transform(state);
        });
      } catch (error) {
        throw TransformationException(
          "On save transformation: ${error.toString()}",
        );
      }

      _printDebug('Serializing');

      var data = serializer.encode(state);

      _printDebug('Running save raw transformations');

      try {
        // Run all raw save transforms
        rawTransforms?.onSave?.forEach((transform) {
          data = transform(data);
        });
      } catch (error) {
        throw TransformationException(
            'On save raw transformation: ${error.toString()}');
      }

      _printDebug('Saving to storage');

      // Save to storage
      try {
        // Use lock to prevent writing twice at the same time
        await _saveLock.synchronized(() async => await storage.save(data));
      } catch (error) {
        throw StorageException('On save: ${error.toString()}');
      }

      _printDebug('Done saving!');
    } catch (error) {
      _printDebug('Error while saving: ${error.toString()}');
      rethrow;
    }
  }

  void _printDebug(Object object) {
    if (debug) {
      print('Persistor debug: $object');
    }
  }
}

我們看幾個(gè)重要的屬性一個(gè)是storage

final persistor = Persistor<AppState>(
storage: FlutterStorage(),
serializer: JsonSerializer<AppState>(AppState.fromJson),
);
官方實(shí)例中給出了一個(gè)FlutterStorage,繼續(xù)點(diǎn)擊看一下這是個(gè)什么東西

class FlutterStorage implements StorageEngine {
  StorageEngine _locationEngine;

  FlutterStorage({
    String key = "app",
    FlutterSaveLocation location = FlutterSaveLocation.documentFile,
  }) {
    switch (location) {
      case FlutterSaveLocation.documentFile:
        _locationEngine = DocumentFileEngine(key);
        break;
      case FlutterSaveLocation.sharedPreferences:
        _locationEngine = SharedPreferencesEngine(key);
        break;
      default:
        throw StorageException("No Flutter storage location");
    }
  }

看到了其實(shí)就是讓我們方便設(shè)置保存的位置,默認(rèn)是FlutterSaveLocation.documentFile我們也可以設(shè)置成 FlutterSaveLocation.sharedPreferences
好看第二個(gè)serializer這里就不在粘貼源碼了,有興趣的朋友可以點(diǎn)進(jìn)去看一下就是我們儲(chǔ)存數(shù)據(jù)的格式我們可以使用JsonSerializer這個(gè)時(shí)候我們要在狀態(tài)類里提供兩個(gè)方法吧我們想要保存的數(shù)據(jù)json化

class CountState{
  int _count;
  get count => _count;
  CountState(this._count);
  CountState.initState() : _count = 0;
  static CountState fromJson(dynamic json) => json != null ? CountState(json['count'] as int) : CountState(0);
  dynamic toJson() => {'count': _count};
}

然后我們提供一個(gè)方法用他來保存狀態(tài)

Future<Store<CountState>> InitializeStore() async {
  final persistor = Persistor<CountState>(
    throttleDuration: Duration(seconds: 5),
    //debug: true,
    storage: FlutterStorage(),
    serializer:
    JsonSerializer<CountState>(CountState.fromJson), // Or use other serializers
  );
      // 從 persistor 中加載上一次存儲(chǔ)的狀態(tài)
  final initialState = await persistor.load();
  final store = Store<CountState>(
      reducer,
      initialState: initialState ?? CountState(0),
      middleware: [persistor.createMiddleware()]
  );
  return store;
}

然后我們?cè)趓unApp的頭上調(diào)用我們定義的方法

  Store< CountState > store = await InitializeStore();

這樣就可以保存我們的狀態(tài)了

寫在最后

因?yàn)槭且苿?dòng)端出身,很多理解不是很到位,歡迎指正.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末彪腔,一起剝皮案震驚了整個(gè)濱河市熟吏,隨后出現(xiàn)的幾起案子骂倘,更是在濱河造成了極大的恐慌还蹲,老刑警劉巖资昧,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件富玷,死亡現(xiàn)場(chǎng)離奇詭異嚎京,居然都是意外死亡馆揉,警方通過查閱死者的電腦和手機(jī)业舍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來升酣,“玉大人舷暮,你說我怎么就攤上這事∝眩” “怎么了下面?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)巢墅。 經(jīng)常有香客問我诸狭,道長(zhǎng)券膀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任驯遇,我火速辦了婚禮芹彬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘叉庐。我一直安慰自己舒帮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布陡叠。 她就那樣靜靜地躺著玩郊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枉阵。 梳的紋絲不亂的頭發(fā)上译红,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音兴溜,去河邊找鬼侦厚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拙徽,可吹牛的內(nèi)容都是我干的刨沦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼膘怕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼想诅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岛心,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤来破,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鹉梨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讳癌,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年存皂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逢艘。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旦袋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出它改,到底是詐尸還是另有隱情疤孕,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布央拖,位于F島的核電站祭阀,受9級(jí)特大地震影響鹉戚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜专控,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一抹凳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伦腐,春花似錦赢底、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咳焚,卻和暖如春洽损,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背革半。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工碑定, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人督惰。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓不傅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親赏胚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子访娶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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