Flutter再開しようと思ったときにやったことのメモ。作業ログ的な備忘録。
インストールまでは終わったので、いろいろ思い出す。
とりあえず、過去に書いた記事を読み直す
Flutterのタグをつけていた記事を見直す。
この記事が、わりとちゃんと知りたいことをまとめてあった、えらい(´ω`)
- Flutterに入門して疑問に思ったことと、そのとき調べたこと - くらげになりたい。
- 【Flutter】Riverpodを使って状態を管理する - くらげになりたい。
- Flutterで画面遷移するときのいろいろ(Navigator / PageRouteBuilder) - くらげになりたい。
Dartの特徴、ディレクトリ構成、UI関連(StatelessWidget/StatefulWidget)など思い出してきた。
lib配下のディレクトリ構成を決める
とりあえず、ディレクトリ構成を決める。
前に考えたシンプルな構成をベースに拡張。
lib/ ├── configs ... 共通の設定関連 ├── domain ... コアの処理関連 │ └── models ... モデル関連 ├── pages ... ページなどのUI関連 │ └── widgets ... ページ内で使うWidget └── main.dart ... メイン。テーマのカスタムやルーティングも
必要なライブラリを入れる
Riverpod
とりあえず、状態管理にRiverpodを入れる。
# pubspec.yaml dependencies: flutter: sdk: flutter flutter_hooks: ^0.18.0 hooks_riverpod: ^2.0.0-dev.5
flutter pub get
で変更を反映。
Riverpodの使い方
以前、調べてたときと少し変わっているっぽい。
import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: appName, theme: appTheme, home: const ProviderScope( child: MyHomePage(title: 'Flutter Demo Home Page'), ), ); } }
ProviderScope
をつけるのは変わらず。
import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; // provider final homeProvider = StateNotifierProvider<HomeState, Counter>((ref) => HomeState()); // state class class HomeState extends StateNotifier<Counter> { HomeState() : super(const Counter()); void countUp() { state = Counter(count: state.count + 1); } } // state data @immutable class Counter { const Counter({this.count = 0}); final int count; } class MyHomePage extends HookConsumerWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override Widget build(BuildContext context, WidgetRef ref) { final state = ref.watch(homeProvider); final provider = ref.read((homeProvider.notifier)); return Scaffold( appBar: AppBar(title: Text(title)), body: Center( child: Column( children: <Widget>[ Text('${state.count}'), ], ), ), floatingActionButton: FloatingActionButton( onPressed: provider.countUp, child: const Icon(Icons.add), ), ); } }
呼び出し方が少し違う感じ。
StateNotifierProvider
の型が第2引数を取るようにStateNotifier
が完全にイミュータブルにHookConsumerWidget
かConsumerWidget
を継承するようにuseProvider
がなくなり、WidgetRef(ref)
を使うように
今の使い方はこのあたり。
・プロバイダとは | Riverpod
・プロバイダの利用方法 | Riverpod
変更点などは、このあたり。
・^0.13.0 → ^0.14.0 | Riverpod
プロバイダの種類
各プロバイダの種類はこんな感じ。
プロバイダの種類 | 生成されるステートの型 | 具体例 |
---|---|---|
Provider | 任意 | サービスクラス / 算出プロパティ(リストのフィルタなど) |
StateProvider | 任意 | フィルタの条件 / シンプルなステートオブジェクト |
FutureProvider | 任意のFuture | API の呼び出し結果 |
StreamProvider | 任意のStream | API の呼び出し結果のStream |
StateNotifierProvider | StateNotifierのサブクラス | イミュータブル(インタフェースを介さない限り)で複雑なステートオブジェクト |
ChangeNotifierProvider | ChangeNotifier のサブクラス | ミュータブルで複雑なステートオブジェクト |
・プロバイダの種類 | プロバイダとは | Riverpod
refを使ったプロバイダを利用方法
使い方は以下の通り。
ref.watch
- プロバイダの値を取得した上で、その変化を監視する。値が変化すると、その値に依存するウィジェットやプロバイダの更新が行われる。
ref.listen
- プロバイダの値を監視し、値が変化するたびに呼び出されるコールバック関数(画面遷移、ダイアログの表示など)を登録する。
ref.read
- プロバイダの値を取得する(監視はしない)。クリックイベント等の発生時に、その時点での値を取得する場合に使用できる。
ステートの値は、ref.watch
かref.listen
。(ref.watch(provider)
)
ステート自体を取得する場合は、ref.read
がよい。(ref.read((provider.notifier))
)
watch メソッドは ElevatedButton の onPressed 内など、非同期的な場面で呼び出さないでください。
また initState を始め、State のライフサイクルメソッド内での使用も避けてください。これらの場合は代わりに ref.read を使用してください。
・ref.watch を使ってプロバイダを監視する | プロバイダの利用方法 | Riverpod
flutter_hooks
flutter_hooksに関しては、公式ドキュメントとこの記事がわかりやすかった。
・flutter_hooks | Flutter Package
・Flutter HooksのuseXXXの使い方 - Qiita
ライフサイクル
ライフサイクルには、アプリのライフサイクル(AppLifecycleState
)と
画面のライフサイクル(StatefulWidget
)があるよう。
- アプリのライフサイクル(
AppLifecycleState
) - 画面のライフサイクル(
StatefulWidget
)
AppLifecycleState
は、WidgetsBindingObserver
を使わないと取得できないよう。
StatefulWidget
はWidgetのライフサイクルのため、
AndroidのActivityのようなライフサイクルを見たい場合は、アプリのサイクルを見る必要がある。
以上!! だいぶ思い出してきた(´ω`)