はじめに
Flutterアプリケーションでリアルタイムにデータを保存・同期させるには、Firebase Firestoreが非常に便利です。Firestoreはクラウドデータベースで、データの追加、削除、更新がリアルタイムで反映され、複数のユーザーが同時に利用するアプリケーションに最適です。
この記事では、FlutterアプリでFirestoreを使ってリアルタイムデータを保存・同期する方法を解説します。Firestoreの基本的な操作や、実際にFlutterと連携してリアルタイムにデータを扱う方法を、初心者でも理解できるように丁寧に説明します。
Firebase Firestore のセットアップ
Firebase プロジェクトの作成
まずは、Firebaseにプロジェクトを作成して、Firestoreを有効にします。
Firebaseプロジェクトの作成・プロジェクトの初期化はこちらの記事で説明しています。
Firebase Authenticationのセットアップの手順後に続きを実施してください
(Firebase Authenticationを有効にする必要はありません)

- プロジェクトを作成したら、Firestore Database(Cloud Firestore)を有効化します。
- その後、Firestoreデータベースのモードを「テストモード」に設定します。これにより、初期開発段階で誰でもデータにアクセスできるようになります。
FlutterアプリにFirebaseを追加
次に、FlutterアプリケーションにFirebaseを追加します。
pubspec.yaml
ファイルに以下のパッケージを追加します。(バージョンは適宜変更してください)
dependencies:
firebase_core: ^3.6.0
cloud_firestore: ^5.4.4
- 以下のコマンドを実行してパッケージをインストールします。
flutter pub get
Firestore を使ったデータの保存
Firestoreにデータを保存するためには、Firestoreのインスタンスを使ってコレクションにドキュメントを追加します。
データの追加
cloud_firestore
パッケージを使い、Firestoreにデータを保存する基本的なコードは以下の通りです。
collection('todos')
は、Firestoreのtodos
という名前のコレクション(テーブルのようなもの)にアクセスしています。存在しない場合は自動的に作成されます。add({...})
メソッドは、todos
コレクションに新しいドキュメントを追加するために使用します。
import 'package:cloud_firestore/cloud_firestore.dart';
Future<void> addTodoItem(String task) async {
await FirebaseFirestore.instance.collection('todos').add({
'task': task,
'created_at': Timestamp.now(),
'is_completed': false,
});
}
データの更新
Firestoreに保存されたデータを更新するには、update
メソッドを使います。
doc(id)
: 特定のドキュメント(タスク)を指定するためのメソッドです。ここでは、id
で指定されたドキュメント(タスク)を取得します。update({...})
: 既存のドキュメントのデータを更新します。ここでは、is_completed
フィールドを、関数に渡されたisCompleted
の値に更新しています。
// タスクの更新(Update)
Future<void> updateTodoItem(String id, bool isCompleted) async {
await FirebaseFirestore.instance.collection('todos').doc(id).update({
'is_completed': isCompleted,
});
}
データの削除
データを削除する場合は、delete
メソッドを使用します。
// タスクの削除(Delete)
Future<void> deleteTodoItem(String id) async {
await FirebaseFirestore.instance.collection('todos').doc(id).delete();
}
Firestore のリアルタイム同期
Firestoreの大きな特徴は、データがリアルタイムに同期される点です。FirestoreのStream
を使って、データが変更されたときにリアルタイムで画面に反映する仕組みを実装します。
リアルタイムデータの取得
StreamBuilder
を使って、Firestore内のデータが変更された際に、即座にアプリに反映させる方法を紹介します。
StreamBuilder
:ストリームを監視し、データが更新されるたびに自動でUIを再構築します。Firestoreのリアルタイムのデータを取得するために使います。stream
:FirebaseFirestore.instance.collection('todos').orderBy('created_at').snapshots()
は、Firestoreのtodos
コレクションをcreated_at
フィールドで並べ替え、リアルタイムのスナップショットを取得します。これにより、タスクの追加や変更があればすぐに反映されます。snapshot
: Firestoreから取得されたデータ(QuerySnapshot
)がsnapshot
に渡されます。このスナップショットには、現在のドキュメントの状態(タスクのリスト)が含まれています。
// Firestoreからタスクのリストを取得(Read)
Widget buildTodoList() {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('todos').orderBy('created_at').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
var todos = snapshot.data!.docs;
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
var todo = todos[index];
return ListTile(
title: Text(todo['task']),
trailing: Checkbox(
value: todo['is_completed'],
onChanged: (value) {
updateTodoItem(todo.id, value!); // タスクの更新(Update)
},
),
onLongPress: () {
deleteTodoItem(todo.id); // タスクの削除(Delete)
},
);
},
);
},
);
}
このStreamBuilder
では、Firestore内のtodos
コレクションに変更があった際、即座にデータが取得され、リストビューに反映されます。
完成系のコード
今回作成したコードの完成系です。
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(); // Firebase初期化
runApp(TodoApp());
}
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Firestore Todo App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TodoListScreen(),
);
}
}
class TodoListScreen extends StatefulWidget {
@override
_TodoListScreenState createState() => _TodoListScreenState();
}
class _TodoListScreenState extends State<TodoListScreen> {
// タスクの追加(Create)
Future<void> addTodoItem(String task) async {
await FirebaseFirestore.instance.collection('todos').add({
'task': task,
'created_at': Timestamp.now(),
'is_completed': false,
});
}
// タスクの更新(Update)
Future<void> updateTodoItem(String id, bool isCompleted) async {
await FirebaseFirestore.instance.collection('todos').doc(id).update({
'is_completed': isCompleted,
});
}
// タスクの削除(Delete)
Future<void> deleteTodoItem(String id) async {
await FirebaseFirestore.instance.collection('todos').doc(id).delete();
}
// Firestoreからタスクのリストを取得(Read)
Widget buildTodoList() {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('todos').orderBy('created_at').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
var todos = snapshot.data!.docs;
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
var todo = todos[index];
return ListTile(
title: Text(todo['task']),
trailing: Checkbox(
value: todo['is_completed'],
onChanged: (value) {
updateTodoItem(todo.id, value!); // タスクの更新(Update)
},
),
onLongPress: () {
deleteTodoItem(todo.id); // タスクの削除(Delete)
},
);
},
);
},
);
}
// モーダルを表示してタスクを追加
void _showAddTodoDialog() {
TextEditingController _taskController = TextEditingController();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add a new task'),
content: TextField(
controller: _taskController,
decoration: InputDecoration(hintText: 'Enter task here'),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(); // モーダルを閉じる
},
child: Text('Cancel'),
),
TextButton(
onPressed: () {
if (_taskController.text.isNotEmpty) {
addTodoItem(_taskController.text); // タスクを追加
Navigator.of(context).pop(); // モーダルを閉じる
}
},
child: Text('Add'),
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Firestore Todo List')),
body: buildTodoList(), // タスクのリスト表示
floatingActionButton: FloatingActionButton(
onPressed: _showAddTodoDialog, // モーダルを表示してタスクを追加
child: Icon(Icons.add),
),
);
}
}
まとめ
この記事では、FlutterとFirebase Firestoreを使ったリアルタイムデータの保存・同期について解説しました。Firestoreは、データがリアルタイムに同期されるため、複数のユーザーが同時に使うアプリケーションや、データの即時反映が求められるアプリに最適です。
この記事のポイント
- Firestoreのセットアップ方法とFlutterとの連携。
- データの保存、更新、削除の基本操作。
StreamBuilder
を使ったリアルタイム同期の実装。
これらを活用して、よりインタラクティブでリアルタイム性の高いアプリを作成してみてください。
コメント