第6回:データの保存と取り出し
FlutterにはiOS/Androidの各プラットフォームに搭載された機能を簡単に使うためのライブラリが数多く提供されています。 今回の講義では、ライブラリを活用し、前回作成したTODOアプリを拡張し、データを保存する機能を実現します。
第6回の目標
TODOアプリの拡張を通じて、Flutterライブラリの使い方を学びます。
本日実装するアプリケーション
前回までのTODOアプリでは、動的にタスクカードを追加できるようになっていたと思います。 ただ前回までのアプリでは、追加したカードをアプリ内に保存することはできませんでした。 今回の授業では、追加したタスクを永続的に保存する機能の実装について学びます。
タスクを保存する方法は、
- (1)設定情報として端末内に保存
- (2)アプリ内にテキストファイルとして保存
- (3)アプリ内のデータベースに保存
- (4)サーバのデータベースに保存 などの方法があります。
今回は、最も簡単な(1)を用いた実装方法について練習します。
任意の文字列の取得
データの保存を行う前に、任意の文字列を取得する準備をします。
任意の文字列を取得する方法は様々ありますが、今回は下記示す図のようなAlertDialog
を用いて文字列を取得します。
先に示したサンプルのアラートログを実行するには、下記のコードを使います。 実装中のアプリにコピーアンドペーストして使ってください。
_showTextInputDialog:
関数を実行する、アラートダイアログを表示させ、
文字列を取得します。この際、戻り値はFuture<String?>
になっているので、
文字列自体は非同期で渡されます。そのため、関数の実行にawait
もしくは、.then((value){...})
を用いて非同期に値を取得するようにしてください。
ダイアログ上の「OKボタン」または「キャンセルボタン」が押された後に、
テキストフィールド上の値(文字列)が戻り値として非同期で返されます。
DartPad上で動作するサンプルアプリを準備したいので、 任意の値を取得できるか試してみてください。 必要に応じてカスタマイズすることも可能です。
ライブラリのインストール
Flutterには、様々なライブラリが準備されており、これらを活用することで簡単に様々な機能を追加できます。 ライブラリは、以下のサイトから検索することができます。
設定情報を保存するライブラリのインストール
今回は、アプリ内に任意の情報を保存するライブラリ(shared_preferences)を使って、 作成したTODOリストをアプリ内に保存します。
まずは、shared_preferences
のリンクにアクセスして、内容を確認してみましょう。
pub.devから検索しても、見つけることができます。
画面最上段に、プラグインの名前と最新のプラグインのバージョン情報が記述されています。
同じページの下段には、利用方法が記述されています。
shared_prefrences
プラグインを使うことで、アプリの設定情報など、比較的少量のデータをアプリ内に保存するためのプラグインです。
key-value形式で、任意の値を保存することができます。
Installing
タブをクリックすると、インストール方法が詳細に記述されいます。
インストール手順は以下の通りです。
pubspec.yaml
にshared_preferences
を追加。ライブラリをインポートします。 Android Studio上では、pubspec.yaml
を保存すると、ダウンロードが開始されます。 もし開始されない場合は、ターミナル上でpub get
を実行してください。dependencies: shared_preferences: ^2.0.11
shared_prefrences
を利用するには、利用するファイル(現時点ではmain.dart
)でプラグインをインポートします。import 'package:shared_preferences/shared_preferences.dart';
shared_prefreneces
を利用するときは、.getInstance()
でSharedPrefrenceのインスタンスを取得して利用します。 この時、.getInstance()
は非同期でインスタンスを返すことに注意してください。 データの保存は、.getXXX()
や.setXXX()
を使います。 どのような形式のデータを保存できるは、shared_prefrences
のドキュメント上で確認できます。 (現時点では、Int
,Double
,Boolean
,String
,StringList
を保存することができます。)
SharedPreferences prefs = await SharedPreferences.getInstance();
// 保存している値を取得
int count = prefs.getInt('count') ?? 0
// 値を保存
prefs.setInt('count', count);
データの保存
TODOリストのアプリを使って、データを保存してみましょう。
DartPad上では、SharedPrefrecnes
を使うことはできないので、
シュミレーターか実機にアプリを書き込むようにしてください。
①〜⑧が前回のTODOアプリケーションから修正した箇所です。
①:必要なライブラリをインポート(今回は、乱数を利用するため、dart:math
のインポートも行います。)
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:math' as math;
② Widgetを初期化した際に呼ばれるinitState()
を上書き
@override
void initState() {
super.initState();
// .... your code is here ..... //
}
③④ initState:
の中で、SharedPreferences
のインスタンスを取得し、
SharedPreferences
に保存されているTODOリストを取得。
取得できた場合は、widget.cards
に取得したTODOリストの情報を反映する。
SharedPreferences.getInstance().then((prefs ) {
var todo = prefs.getStringList("todo") ?? [];
for (var v in todo){
setState(() {
widget.cards.add(TodoCardWidget(label: v));
});
}
});
⑤ TextInputDialogを用いて、任意の文字列を取得する。
var label = await _showTextInputDialog(context);
⑥ SharedPreferencesのインスタンスを取得し、追加する。
SharedPreferences prefs = await SharedPreferences.getInstance();
var todo = prefs.getStringList("todo") ?? [];
todo.add(label);
await prefs.setStringList("todo", todo);
⑦⑧ AppBarを拡張することで、作成したTODOリストをまとめて消すこともできます。 AppBarにゴミ箱ボタンを設置し、削除する場合は自動的に削除してみてください。
appBar: AppBar(
title: const Text("My TODO"),
actions: [
// ⑦ナビゲーションバーの右上にゴミ箱ボタンを設置
IconButton(onPressed: (){
// ⑧ 押された場合は、保存されているTODOを全て削除
SharedPreferences.getInstance().then((prefs ) async {
await prefs.setStringList("todo", []);
setState(() {
widget.cards = [];
});
});
}, icon: Icon(Icons.delete))
],
),
最終的なアプリはこのような実装になります。
複雑なデータを保存する
今の状態ですと、まだ単純な文字列情報しかデータを保存できません。 ボタンの状態など、もう少し複雑な情報を保存するには、 もう少しデータの保存形式を工夫する必要があります。
JSON形式の文字列としてデータを保存することで、より複雑なデータを保存できるようになります。
今回は、以下の形式でデータを保存します。
{
"title":"TODO-1",
"status":true
}
JSON形式の文字列は、Dartの辞書型オブジェクトから変換できます。
import 'dart:convert';
を使って、convert
ライブラリをプロジェクトにインポートします。jsonEncode()
メソッドを使って、辞書型オブジェクトをJSON形式への文字列に変換jsonDecode()
メソッドを使って、JSON形式の文字列を逆に辞書型オブジェクトに変換
TODOリストの保存時に、「JSON形式の文字列」で保存し、取り出し時に「JSON形式の文字列」を「辞書形式のオブジェクト」に変換することで、 より複雑な情報を保存し管理することができます。
- 非同期にカードリストを生成するメソッドを実装(ここでは、
getCards()
メソッド)- JSON形式の文字列を取得し辞書型オブジェクトに変換
- FutureBuilderを使って、
getCards()
メソッドの状態を確認し、作業完了時にカードリストを更新 - チェックボタンが押されたタイミングでボタン状態を設定ファイルに保存
- 該当のカードを検索し、ボタン状態を変更。再度JSON形式の文字列に変更し保存