FlutterでRealmを使ってみた
Realmに入門してみる
RealmというローカルDBがあるのですが、Swiftで個人アプリを作っていたときに使っていたことがあって、Flutterでも使えるそうなので、試してみました。
こちらに公式ドキュメントのリンクも貼っておきます
動画も作りました
やること
- パッケージを追加する
flutter pub add realm
- モデルクラスを作る。今回はPersonというクラスを作ります。
import 'package:realm/realm.dart';
part 'person.g.dart';// person.g.dartは、RealmObjectを継承するクラスから自動生成されます。
()// @RealmModelは、RealmObjectを継承するクラスに付与するアノテーションです。
class _Person {
late String name;// lateをつけるのは、RealmObjectはデフォルトコンストラクタを持たないためです。
}
- Personというクラスを作ったら、Realmを使うのに、必要なファイルを自動生成します
ファイルを自動生成するコマンド
dart run realm generate
自動生成されたファイル
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'person.dart';
// **************************************************************************
// RealmObjectGenerator
// **************************************************************************
class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject {
Person(
String name,
) {
RealmObjectBase.set(this, 'name', name);
}
Person._();
String get name => RealmObjectBase.get<String>(this, 'name') as String;
set name(String value) => RealmObjectBase.set(this, 'name', value);
Stream<RealmObjectChanges<Person>> get changes =>
RealmObjectBase.getChanges<Person>(this);
Person freeze() => RealmObjectBase.freezeObject<Person>(this);
static SchemaObject get schema => _schema ??= _initSchema();
static SchemaObject? _schema;
static SchemaObject _initSchema() {
RealmObjectBase.registerFactory(Person._);
return const SchemaObject(ObjectType.realmObject, Person, 'Person', [
SchemaProperty('name', RealmPropertyType.string),
]);
}
}
Realmの機能を使ってみる
追加と表示の機能は同じページで行っております。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:realm/realm.dart';
import 'package:realm_app/person.dart';
class HomePage extends StatefulWidget {
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late Realm realm;// Realmインスタンスを保持するための変数
final _nameController = TextEditingController();
final _personsController = StreamController<List<Person>>.broadcast();
void initState() {
super.initState();
final config = Configuration.local([Person.schema]);
realm = Realm(config);
_fetchPersons();
}
void dispose() {
_nameController.dispose();
_personsController.close();
super.dispose();
}
// _fetchPersonsは、RealmからPersonのリストを取得し、_personsControllerに追加するメソッド
void _fetchPersons() {
final persons = realm.all<Person>().toList();
_personsController.add(persons);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Realm Example'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
TextField(
controller: _nameController,
decoration: InputDecoration(labelText: '名前'),
),
ElevatedButton(
onPressed: () {
try {
if (_nameController.text.isEmpty) {
throw ('名前が入力されてません!');
}
var person = Person(_nameController.text);
realm.write(() {
realm.add(person);
});
_nameController.clear();
_fetchPersons();
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.toString()),
),
);
}
},
child: const Text('Add Person'),
),
Expanded(
child: StreamBuilder<List<Person>>(
stream: _personsController.stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final person = snapshot.data![index];
return ListTile(
title: Text(person.name),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
realm.write(() {
realm.delete(person);
});
_fetchPersons();
},
),
);
});
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return const Center(
child: Text('データがありません'),
);
}
},
),
),
],
),
),
);
}
}
main.dartでimportしてビルドする
import 'package:flutter/material.dart';
import 'package:realm_app/ui/home_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: HomePage(),
);
}
}
簡単ですが、メモをする機能を作れました
簡単と言っても設定で苦戦しました笑
まとめ
Swiftで使ったときよりは、すぐにアプリは作れました。これがStoryboardだと2時間ぐらい作るのに時間がかかったような?
Flutterだと作り方を知っていれば、30分ぐらいで作れます。
今回は覚えておくべきことは、モデルを作ってファイルを自動生成して、realmを開く変数を用意して、メソッドを使えるようにすることです。
以下に今回使用した公式のコードの解説を書いておきます
データモデルの作成
アプリケーションのデータモデルを定義するには、アプリケーション・コードに Realm モデル・クラス定義を追加します。
Realm モデルクラスを定義する際に考慮すべき点があります:
クラス定義ファイルの先頭に package をインポートする。
例えば、car.dart ファイルに _Car というクラスを定義します。パブリックな RealmObject クラスを生成するには、次の RealmObject クラスの生成 セクションのコマンドを使用します。このコマンドは、Car のようなパブリック・クラスを出力します。
モデルを定義するコードの前に、生成されたファイル名(part car.g.dart)を含めるようにしてください。これは RealmObject クラスを生成するために必要です。
import 'package:realm/realm.dart';
part 'car.g.dart';
()
class _Car {
()
late ObjectId id;
late final String make;
late String? model;
late int? miles;
}
RealmObject クラスの生成
データモデルのクラス Car から RealmObject クラス Car を生成します:
dart run realm generate
レルムを開く
クラスを使います。
クラスを使用して、 スキーマやレルムをローカル専用にするか同期させるかなど、 オープンするレルムの詳細を制御します。
設定をコンストラクタに渡します:
initStateの中で使ったコードですね。
final config = Configuration.local([Car.schema]);
final realm = Realm(config);
オブジェクトの作成
新しいCarを作成するには、Carクラスのインスタンスを生成し、書き込みトランザクション・ブロックのレルムに追加します:
final car = Car(ObjectId(), 'Tesla', model: 'Model S', miles: 42);
realm.write(() {
realm.add(car);
});
オブジェクトの削除
車を削除するには
を呼び出して車を削除する。
メソッドを呼び出すことで車を削除します:
realm.write(() {
realm.delete(car);
});
Discussion