👻

【Flutter × Realm】サービスクラスやコントローラーを使って汎用的にRealmを使う

2023/01/04に公開

初めに/概要

flutterでRealmを汎用的に使用する方法を紹介します。

結論としては、realm専用のサービスクラスを作り、各コントローラーでサービスクラスの関数を呼び出す、ということをしています。

realm以外でも使える方法ですので、参考にしてもらえれば嬉しいです!

対象

flutterにて、realmを汎用的に使ってみたい方

目標

  • realm用のServiceクラスで使って、他ファイルからrealmのDBにデータを作成や取得できるようになる

実装

realmの導入・Modelファイルを作成

こちらは、前回の記事を参考に進めてください!

realm用のサービスクラスを導入

汎用的にrealmを使用可能にするためにサービスクラスを作成します。
realm.service.dartファイルを新規作成し、以下のように実装します。
initialize関数を呼ぶことでrealmを使用可能にするためにrealmのインスタンス化をします。

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

class RealmService {
  static RealmService realmInstance = RealmService(); // サービスクラスのインスタンス化
  
  late Realm realm;
  final config = Configuration.local([Member.schema, Department.schema]); //作成したschemaをconfig内に設定

  // realmを使用可能にするために初期化(realmのインスタンス化)します。
  void initialize() {
    realm = Realm(config);
  }
}

realmをインスタンス化する

MyApp()を呼び出すタイミング(=main関数内で呼ばれる)でrealmのインスタンス化を行います。

main.dart
class MyApp extends StatelessWidget {
  MyApp({super.key}) {
    RealmService.realmInstance.initialize();
  }
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

realmを汎用的に使ってみる

Realmサービス内でRealmでCRUDする処理を追加する

今回はCreatとReadの処理を実装します。

realm.service.dart

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

class RealmService {
  static RealmService realmInstance = RealmService();
  late Realm realm;
  final config = Configuration.local([Member.schema, Department.schema]);
  
  // CREATE: realmのMemberテーブルにmemberを追加する処理
  void addMember(Member member) {
    realm.write(() => realm.add(member));
  }

  // READ: realmのMemberテーブルを参照する処理
  List<Member> getMembers(String query) => realm.all<Member>().query(query).toList();

  void initialize() {
    realm = Realm(config);
    print('realmPath: ${config.path}');
  }
}

ページ用のコントローラーを用意

ビジネスロジックはコントローラーで行いたいため、realmを使用するロジックはコントローラーで書きます。

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

class MainController {
  void getDepartments() {
    final departments = RealmService.realmInstance.getDepartments('TRUEPREDICATE SORT(id ASC)');
    print('department一覧: $departments');
  }
  // realmサービスのgetMembers(Read処理)関数を実行
  void getMembers() {
    final members =
        RealmService.realmInstance.getMembers('TRUEPREDICATE SORT(id ASC)');
    print('全member数: ${members.length}');
  }

  // realmサービスのaddMember(Creat処理)関数を実行
  void addMember(int counterNum) {
    final member = Member(
      ObjectId(),
      'Hana Kojima$counterNum',
      'hana.kojima$counterNum@sample.com',
    );
    RealmService.realmInstance.addMember(member);
    // realmに追加されたかを確認するために、Memberテーブルを参照
    final members =
        RealmService.realmInstance.getMembers('TRUEPREDICATE SORT(id ASC)');
    print('追加後: 全member数: ${members.length}');
    for (var member in members) {
      print(member.name);
    }
  }

  // MainController内の処理を使用可能にするためにインスタンス化
  MainController();
}

ページ用のコントローラーを用意

ビジネスロジックを記載したコントローラーをページで扱えるようにし、処理の実行をします。
floatingActionButtonを押下することで、コントローラーのaddMember関数を実行させます。

main.dart
import 'package:flutter/material.dart';
import './main.controller.dart';
import './realm.dart';

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

class MyApp extends StatelessWidget {
  MyApp({super.key}) {
    RealmService.realmInstance.initialize();
  }
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // MainControllerをインスタンス化
  final MainController mainController = MainController();
  int _counter = 0;

  @override
  void initState() {
    // MainController内のgetMembers関数を実行
    mainController.getMembers();
    super.initState();
  }

  // MainController内のaddMember関数を実行
  void _addMember() {
    setState(() {
      _counter++;
    });
    mainController.addMember(_counter);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Realm sample'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _addMember,
        tooltip: 'AddMember',
        child: const Icon(Icons.add),
      ),
    );
  }
}

最後に

このように、realmをどこでも使用可能にする実装を紹介しました。
realm以外でもサービスクラスやコントローラーを用意することで、汎用的にわかりやすく実装することが可能です。

以上で終了です。お疲れ様でした!
参考になった方は、ぜひ、いいねをいただけると嬉しいです!

サンプルコードとして、githubのソースコードを共有します。

Discussion