Flutter 初心者が知りたい小技集 ④ SharedPreferencesでMapを扱う

## はじめに

今回は Flutter における簡易ローカルストレージとして有名な Shared preferences についての小技です。

> [公式](https://pub.dev/packages/shared_preferences)

その他小技集

> [Flutter 初心者が知りたい小技集 ① ウィジェットの分割](https://qiita.com/em0/items/6ade4e9721a9135f4dc8)

> [Flutter 初心者が知りたい小技集 ② ナビゲーションの書き方](https://qiita.com/em0/items/e40ae622b43d7dfd5bc0)

> [Flutter 初心者が知りたい小技集 ③ async と await を使った http 通信](https://qiita.com/em0/items/396851bcd213dff4422e)

## プロジェクト作成

`flutter create local_storage_sample`

## 前準備

パッケージをインストールします。

```
// pubspec.yaml
dependencies:
  shared_preferences: ^0.5.8
```

## 実装

main.dart に実装していきます。まずは初期生成されるカウンターアプリに値が保持されるよう追加してみます。(余計なコメントは消去済み)

```
// lib/main.dart
import 'package:shared_preferences/shared_preferences.dart';
.
.
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() async {
    setState(() {
      _counter++;
    });
    _setCounter(_counter);
  }

  // 値をストレージに保存
  Future<void> _setCounter(count) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('counter', count);
  }

  // 値をストレージから取得
  Future<void> _getCounter() async {
    final prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = prefs.getInt('counter') ?? 0;
    });
  }

  // 初回にストレージから値を取得して設定
  @override
  void initState() {
    super.initState();
    _getCounter();
  }
.
.
```

さて、Shared preferences では通常 int, double, bool, String, そして String 型のリストしか保存できません。Map などのデータを保存したいときにはどうするのか？json 形式に変換します。例としてボタンを押した時間とメッセージを合わせて保存してみましょう。

```
// lib/main.dart
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
.
.
  Future<void> _setCounter(count) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    // 日時を取得
    final pushedAt = DateTime.now().toIso8601String();
    // 保存データを作成
    final countData = json.encode({
      'count': count,
      'pushedAt': pushedAt,
    });
    // Stringとして保存
    await prefs.setString('countData', countData);
  }

  Future<void> _getCounter() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    // キーがあるかを確認
    if (!prefs.containsKey('countData')) {
      return;
    }
    setState(() {
      final countData = json.decode(prefs.getString('countData'));
      print(countData['pushedAt']);
      _counter = countData['count'] ?? 0;
    });
  }
.
.
```

変わらず画面にカウントが保存され、押した時間も一度に保存できていることが確認できます。

```
Restarted application in 675ms.
flutter: 2020-08-05T13:25:55.740282
```

## おまけ

- キーがあるか確認

  既に出てきましたが、存在しないキーを参照しようとするとエラーになるので

  ```
  // キーがあるかを確認
  if (!prefs.containsKey('countData')) {
    return;
  }
  ```

  とチェックしましょう。

- 一括削除

  個別に上書きもできますが一気に削除したい場合は

  ```
  prefs.clear();
  ```

  でできます。

  追加で実装するとこちらになります。

  ```
  .
  .
  Future<void> clearPrefs() async {
      final prefs = await SharedPreferences.getInstance();
      prefs.clear();
      setState(() {
        _counter = 0;
      });
  }
  .
  .
  body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
              FlatButton(
                child: Text("CLEAR"),
                onPressed: () {
                  clearPrefs();
                },
              )
            ],
          ),
        ),
  .
  .
  ```

## 最後に

今回は SharedPreferences についてでした。サーバへログイン処理をした際の返り値をデバイスへ保存するなど色々な部分で活用できそうですね。

最後まで読んでくださりありがとうございました。