Googleによって開発されたフリーかつオープンソースのモバイルアプリケーションフレームワークであるFlutterを用いてTodoアプリを作成してみました。
※Kotlin版はこちら
完成形は以下です。
![](https://tokku-engineer.tech/wp-content/uploads/2020/11/Screenshot_1606635626-576x1024.png)
全ソースコードはこちら
またTodoアプリを題材に、KotlinとFlutterの比較記事も書いています。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fcdn.qiita.com%2Fassets%2Fpublic%2Fadvent-calendar-ogp-background-7940cd1c8db80a7ec40711d90f43539e.jpg?ixlib=rb-4.0.0&w=1200&mark64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZ3PTk3MiZoPTM3OCZ0eHQ9VE9ETyVFMyU4MiVBMiVFMyU4MyU5NyVFMyU4MyVBQSVFMyU4MSVBNyVFNiVBRiU5NCVFOCVCQyU4MyVFMyU4MSU5OSVFMyU4MiU4QkFuZHJvaWQlMjhNVlZNJTI5JUUzJTgxJUE4Rmx1dHRlciUyOFByb3ZpZGVyJTI5JUUzJTgxJUFFJUU5JTgxJTk1JUUzJTgxJTg0JnR4dC1hbGlnbj1sZWZ0JTJDdG9wJnR4dC1jb2xvcj0lMjMzQTNDM0MmdHh0LWZvbnQ9SGlyYWdpbm8lMjBTYW5zJTIwVzYmdHh0LXNpemU9NTYmcz1hNTFmNWY1ODY2MzM3MGRlMDM2ZGQwYzE1ZDY0MmZjOA&mark-x=120&mark-y=96&blend64=aHR0cHM6Ly9xaWl0YS11c2VyLWNvbnRlbnRzLmltZ2l4Lm5ldC9-dGV4dD9peGxpYj1yYi00LjAuMCZoPTc2Jnc9OTcyJnR4dD0lNDB0b2trdW41NTUyJnR4dC1jb2xvcj0lMjMzQTNDM0MmdHh0LWZvbnQ9SGlyYWdpbm8lMjBTYW5zJTIwVzYmdHh0LXNpemU9MzYmdHh0LWFsaWduPWxlZnQlMkN0b3Amcz01OGNhNDMwZDM4N2M4MDlhOWU0ZDFjMWUxYWIxZGQ1NQ&blend-x=120&blend-y=445&blend-mode=normal&txt64=aW4gRmx1dHRlcuWkp-Wtpg&txt-width=972&txt-clip=end%2Cellipsis&txt-color=%233A3C3C&txt-font=Hiragino%20Sans%20W6&txt-size=36&txt-x=134&txt-y=546&s=528c56db538f11dc9ef371a778fb8c89)
アーキテクチャ概要
ざっくりとした全体像です。
![](https://tokku-engineer.tech/wp-content/uploads/2020/11/TODOAppFlutter-1024x576.png)
一覧画面(main.dart)と詳細画面(TodoItemDetailPage)に2画面構成で、画面遷移自体もNavigator.push()とpop()でそのまま行います。
画面はどちらもStatelessWidgetで実装し、それぞれのModel(MVVMで言うところのViewModel)に持たせます。
また、RealmのFlutterプラグインがあまり使えなかったので、SQLiteを使いました。
pubspec.yaml抜粋
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.0
provider: ^4.3.2+2
sqflite: ^1.3.2+1
shared_preferences: ^0.5.12+4
メイン画面
ChangeNotifierProvider<MainModel>を返却するようにし、MainModelはChangeNotifierを継承します。
これでConsumer<MainMode>内でMainModelが使えるようになります。
中身はListViewでMainModelのリストをListTileにmapして表示しているだけです。
Modelでは上述の通り、ChangeNotifierを継承して実装します。これで、メソッド内で非同期処理が走っても、await で待った後にnotifyListener()とすると、勝手に再描画してくれます。
DBへの実際の処理はTodoItemRepositoryに記載し、ここではそれを呼び出すだけとしています。
詳細画面
特筆すべきことはあまりありませんが、コード量が少ないこともあって、ボタンを押したときの例外処理もここでしてしまっています。
それでも改行しまくっても全体のコードは100行以下です。
詳細ページは更新処理と新規作成両方で使っているので、addメソッドとupdateメソッドを定義しています。
空で渡ってきたりnullで渡ってきたときの分岐を書いているくらいで、ほとんどはTodoItemRepositoryにDBのクエリを記載しています。
SQLite周り
まずDatabaseProviderというクラスをシングルトンで定義します。
こうすることで、初めてDatabaseProviderにアクセスしたときだけinitDatabase()を実行し、次からは同じインスタンスを見るようになります。
次に、Entityを用意します。ここではTodoItemという名前で以下のフィールドを定義しました。
フィールドとgetter定義の他に、SQLiteとのやり取りのためにtoMapとfromMapを定義しています。
DBから渡ってくるのはjsonなので、変換してやる必要があります。
そして、これらを使うためのRepositoryクラスを用意します。
一部しか載せていませんが、insertやdeleteは用意されているものの、rawQueryを書いてSELECTしています。
Realmよりも若干めんどくさいイメージです。
おまけ(完了済みアイテムの表示/非表示切替)
また、Kotlin版の方では実装していませんが、あまりにもFultterが簡単すぎるので、完了済みのアイテムの表示/非表示を切り替えれるようにしました。
SharedPreferenceを使えるようなので、ProviderクラスとしてPersistenceStorageProviderクラスを用意してシングルトンでSharedPreferenceを準備し、StorageRepositoryクラスを各modelから呼んでいます。
まとめ
FlutterのProviderパターンは状態管理が非常にすっきりして、何よりこれでAndroidとiOS両方実装できるので開発スピードが非常に速そうな印象です。
SQLiteはRealmと比べると少し冗長な気がしますが、ローカルDBを使うより、FirebaseなどのmBaaSを使うことの方が多いかと思いますので、あまり欠点とも言えなさそうです。
- 全コードはこちら
参考:
コメント