Open1

FlutterでRealmを使ってみる

JboyHashimotoJboyHashimoto

FlutterでRealmを使ってみた

ドキュメントぐらいしか参考になるものがない?
https://pub.dev/packages/realm

困ったこと

データを保存して、画面が更新されないとStreamでデータを表示できなかった!

まずはモデルクラスを作る

item.dart
import 'package:realm/realm.dart';

part 'item.g.dart';

()
class _Item {
  late String name;
  late int quantity;
}

コマンドを打ってファイルを自動生成する

flutter pub run realm generate

自動生成されたファイル

item.g.dart
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'item.dart';

// **************************************************************************
// RealmObjectGenerator
// **************************************************************************

class Item extends _Item with RealmEntity, RealmObjectBase, RealmObject {
  Item(
    String name,
    int quantity,
  ) {
    RealmObjectBase.set(this, 'name', name);
    RealmObjectBase.set(this, 'quantity', quantity);
  }

  Item._();

  
  String get name => RealmObjectBase.get<String>(this, 'name') as String;
  
  set name(String value) => RealmObjectBase.set(this, 'name', value);

  
  int get quantity => RealmObjectBase.get<int>(this, 'quantity') as int;
  
  set quantity(int value) => RealmObjectBase.set(this, 'quantity', value);

  
  Stream<RealmObjectChanges<Item>> get changes =>
      RealmObjectBase.getChanges<Item>(this);

  
  Item freeze() => RealmObjectBase.freezeObject<Item>(this);

  static SchemaObject get schema => _schema ??= _initSchema();
  static SchemaObject? _schema;
  static SchemaObject _initSchema() {
    RealmObjectBase.registerFactory(Item._);
    return const SchemaObject(ObjectType.realmObject, Item, 'Item', [
      SchemaProperty('name', RealmPropertyType.string),
      SchemaProperty('quantity', RealmPropertyType.int),
    ]);
  }
}

作ってみたアプリのコード

nullだと例外処理が発生するので、エラーハンドリングして対処した。いいサンプルが作れなかった。

main.dart
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:realm/realm.dart';
import 'item.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  late Realm realm;
  final _nameController = TextEditingController();
  final _quantityController = TextEditingController();
  final _itemsController = StreamController<List<Item>>.broadcast();

  
  void initState() {
    super.initState();
    final config = Configuration.local([Item.schema]);
    realm = Realm(config);
    _fetchItems();
  }

  
  void dispose() {
    _itemsController.close();
    _nameController.dispose();
    _quantityController.dispose();
    super.dispose();
  }

  void _fetchItems() {
    final items = realm.all<Item>().toList();
    _itemsController.add(items);
  }

  
  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: 'アイテム名'),
            ),
            TextField(
              controller: _quantityController,
              decoration: InputDecoration(labelText: '個数'),
              keyboardType: TextInputType.number,
            ),
            ElevatedButton(
              onPressed: () {
                try {
                  if (_nameController.text.isEmpty) {
                    throw ('名前が入力されてません!');
                  }

                  if (_quantityController.text.isEmpty) {
                    throw ('数量が入力されてません!');
                  }

                  var item = Item(_nameController.text,
                      int.parse(_quantityController.text));
                  realm.write(() {
                    realm.add(item);
                  });
                  _nameController.clear();
                  _quantityController.clear();
                  _fetchItems();
                } catch (e) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(
                      content: Text(e.toString()),
                    ),
                  );
                }
              },
              child: const Text('Add Item'),
            ),
            Expanded(
              child: StreamBuilder<List<Item>>(
                stream: _itemsController.stream,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return ListView.builder(
                        itemCount: snapshot.data!.length,
                        itemBuilder: (context, index) {
                          final item = snapshot.data![index];
                          return ListTile(
                            title: Text(item.name),
                            subtitle: Text(item.quantity.toString()),
                            trailing: IconButton(
                              icon: const Icon(Icons.delete),
                              onPressed: () {
                                realm.write(() {
                                  realm.delete(item);
                                });
                                _fetchItems();
                              },
                            ),
                          );
                        });
                  } else if (snapshot.hasError) {
                    return Text('Error: ${snapshot.error}');
                  } else {
                    return const Center(
                      child: Text('アイテムがありません'),
                    );
                  }
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}