FlutterでRiverpodとSharedPreferencesを使った状態の永続化ガイド【初心者向け】
生徒
「Flutterでアプリを再起動しても状態を保持したいんですが、どうすればいいですか?」
先生
「それなら、RiverpodとSharedPreferencesを組み合わせることで、簡単に状態の永続化ができますよ。」
生徒
「RiverpodでどうやってSharedPreferencesを使うんですか?」
先生
「それでは、FlutterのRiverpodとSharedPreferencesを組み合わせた状態管理と永続化の基本的な実装方法を見ていきましょう。」
1. Riverpodとは?Flutterでの状態管理の定番
Flutterアプリで状態管理といえば、Riverpodは今や定番のライブラリです。従来のProviderよりも強力で、テストしやすく、グローバルアクセスや依存関係の注入も簡単にできます。
Flutterでアプリの状態を適切に管理することは、UIの一貫性やバグの回避に非常に重要です。特にユーザーの設定情報やカウンターの値など、アプリを再起動しても保持したい状態がある場合は、RiverpodとSharedPreferencesを連携させるのが効果的です。
2. SharedPreferencesとは?Flutterで簡単にデータ保存
SharedPreferences(シェアード・プリファレンス)は、Flutterアプリ内で簡単にキーと値のペア(Key-Value形式)のデータを保存・読み込みできる便利なパッケージです。
例えば、ログイン状態やテーマ設定、カウンターの数値など、軽量な永続データを保存するのに最適です。
shared_preferencesパッケージを使えば、ローカルストレージにデータを書き込んで、アプリを閉じても値を保持することが可能になります。
3. Flutterプロジェクトに必要なパッケージを追加
まずは、pubspec.yamlファイルに以下の2つのパッケージを追加しましょう。
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.0.0
shared_preferences: ^2.0.0
追加後は、下記のコマンドで依存関係をインストールします。
flutter pub get
Flutterを「実務レベル」で使えるようになりたい人や、 iPhone / Android両対応アプリ開発の流れをまとめて学びたい人には、 定番の実践書がこちらです。
Flutter実践開発をAmazonで見る※ Amazon広告リンク
4. 永続化用の状態プロバイダーを作成しよう
以下は、FlutterでSharedPreferencesを使ってcounterの状態を保存・復元するためのサンプルコードです。
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0) {
_loadCounter();
}
void _loadCounter() async {
final prefs = await SharedPreferences.getInstance();
state = prefs.getInt('counter') ?? 0;
}
void increment() async {
state++;
final prefs = await SharedPreferences.getInstance();
await prefs.setInt('counter', state);
}
}
このコードでは、アプリ起動時にSharedPreferencesから保存されたcounterの値を読み込み、increment()が呼ばれるたびに値を更新・保存しています。
5. FlutterのUIと連携してみよう
作成したcounterProviderをFlutterのUIと連携して、状態管理を確認しましょう。
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Riverpod 永続化サンプル',
home: const CounterScreen(),
);
}
}
class CounterScreen extends ConsumerWidget {
const CounterScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
final counterNotifier = ref.read(counterProvider.notifier);
return Scaffold(
appBar: AppBar(title: const Text('カウンター(永続化あり)')),
body: Center(
child: Text(
'現在のカウント:$count',
style: const TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => counterNotifier.increment(),
child: const Icon(Icons.add),
),
);
}
}
このようにすることで、アプリを再起動しても前回のカウント値が維持されるようになります。
6. SharedPreferencesと非同期処理の注意点
SharedPreferences.getInstance()は非同期(Future)で値を取得するため、初期化時に正しいタイミングで呼び出すことが重要です。
特にStateNotifierのconstructor内で非同期処理を呼ぶ際は、データが読み込まれる前にUIが更新されないよう注意しましょう。初期値を0にしつつ、非同期で更新するのが一般的です。
7. 他の型(Stringやbool)を保存する方法
SharedPreferencesではint以外にもStringやbool、double、List<String>なども保存可能です。
例えば、ユーザー名を保存するなら次のようにします:
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', 'flutter_user');
String name = prefs.getString('username') ?? '';
このように用途に応じて様々な情報を保存して、アプリの使い勝手を向上させることができます。
8. よくあるエラーと対処法
Flutter初心者がSharedPreferencesやRiverpodでつまずきやすいエラーとして、以下のようなものがあります。
- 非同期処理の取り扱いミス:
awaitを忘れてnullが返ってくる - Providerの未登録:
ProviderScopeをルートに設定していない - 古いパッケージバージョンの利用:
flutter pub upgradeで最新に
これらはエラーメッセージをよく読み、対処することで初心者でも問題なく構築できます。
9. Flutterアプリでの状態永続化の応用例
実際のアプリ開発では、次のような場面でもSharedPreferencesとRiverpodの組み合わせが活躍します。
- ダークモードの設定
- チュートリアル表示済みフラグ
- ログイン状態の保持(簡易的な記録)
- アプリの言語設定
どれも永続化があることで、UXが向上し、ユーザーが快適にアプリを利用できるようになります。