【Kotlin/Firebase】Realtime Databaseの導入と実装方法!クラウドデータベース

この記事からわかること

  • Kotlin/Firebase作成したAndroidアプリRealtime Database導入する方法
  • データベース作成書き込み/読み取りなどの操作方法
  • setValueメソッドupdateChildrenaddValueEventListenergetの使い方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

Firebaseの概要や登録方法については下記記事を参考にしてください。

Realtime Databaseとは?

Firebase Realtime Databaseとはリアルタイムでデータを保存してユーザー間で同期することができるクラウドホスト型NoSQLデータベースです。

Webアプリとモバイルアプリに同じデータを表示させたり、異なるユーザー同士に同じデータを表示させることで共有可能なアプリを作成することができるようになります。

またFirebase Realtime Databaseはデータをサーバーとローカルの2箇所に保持します。ローカルにデータをキャッシュすることでオフラインになってもデータ表示を継続して行えるようになっており、再びオンラインに戻った際に自動でデータを同期してくれます。

アプリからの操作は基本的にはローカルに書き込み処理を行い、サーバーと接続できるタイミングでサーバーと同期します。

データの管理方法

データの保存先は3箇所から選択できるようになっています。同じプロジェクト内でも異なるロケーションにデータベースを構築することができるようです。

公式ドキュメント:リアルタイムデータベースの場所

そして実際のデータはJSON形式で蓄積、管理されていきます。テーブルやレコードではなく、ツリー上になったJSON形式の構造でデータは管理されます。そのため入れ子にできるのは32レベルまでと制限が設けられています。

AndroidアプリにRealtime Databaseを導入する流れ

公式ドキュメント:Realtime Databaseのセットアップ方法

流れ

  1. Firebaseプロジェクトを作成
  2. データベースの作成
  3. Androidアプリの登録
  4. google-services.jsonの追加
  5. gradleにSDK追加
  6. 完了

ここでは通常の「Firebaseプロジェクトを作成」や「Androidアプリの登録」、「google-services.jsonの追加」などの手順は割愛しています。詳細は以下の記事を参考にしてください。

【Android Studio】Firebaseの導入方法!Firebase Analytics/Google Analytics

2.データベースの作成

Firebaseプロジェクトを作成したら、プロジェクト内にデータベースを作成しておきます。左側メニューの「Realtime Database」>「データベースを作成」をクリックします。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

続いてロケーションを問われるので「米国」にして進めていきます。(※あれば米国ではなく東京(asia-northeast1)か大阪(asia-northeast2)のが良いかもです。)

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

データベースの設定は本番環境であればロックモードで、練習であればテストモードにチェックを入れて「有効にする」をクリックします。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

ロックモードを指定した場合はクライアントがデータの読み取り/書き取りができない状態になっているので「ルール」のfalsetrueに変更しておきます。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

ここまできたらプロジェクトにAndroidアプリを登録しておき、「google-services.json」を設置しておいてください。

5.gradleにSDK追加

続いて「build.gradle」にRealtime DatabaseのFirebase SDK(Software Development Kit)を追加していきます。

dependencies {  
  // 〜〜〜〜〜〜〜〜〜〜
  // Firebase Realtime Database
  implementation("com.google.firebase:firebase-database-ktx")
}

これで準備は完了です。

使用方法

ここからはAndroidアプリ内でRealtime Databaseを操作する方法をまとめていきます。Androidアプリから操作するとリアルタイムでデータベース内のデータが変更されていくのを「データ」の中から確認することができます。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

データベースへの参照

まずはDatabaseReferenceインスタンスを生成してRealtime Databaseへ参照できるようにする必要があります。Firebase.databaseでデータベースをreferenceで参照を取得することができます。

import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase

val ref = Firebase.database.reference

データの書き込み処理

データの書き込み処理setValueメソッドを使用します。引数に書き込みたいデータを渡します。childメソッドを使用することで書き込む階層をネストさせることができます。

ref.child("users").setValue("Hello, World!")

Map型を渡すことでキーと値の関係で保存することもできます。

val user = mapOf("username" to "ame")
ref.child("users").setValue(user)

例えば上記のコードを実行するとデータベース内は以下のようになります。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

書き込みに使用できるデータ型

setValueメソッドに引数に渡してデータの書き込みができるのは以下のデータ型のようです。

独自のデータクラスも書き込みができるようで、その際はプロパティ名がキー部分になるようです。

データの更新処理

データの更新処理setValueメソッドを使用してそのまま上書きするだけです。また先ほどと同様の値を変更するには以下のようにchildメソッドチェーンでつなぐ方法childに渡すパスを「/」で区切って指定することも可能です。以下は全て同じ深さのデータを変更しています。

val user = mapOf("username" to "ame")
ref.child("users").setValue(user)
ref.child("users").child("username").setValue("ame")
ref.child("users/username").setValue("ame")

しかしsetValueメソッドは指定した階層の値を新規で追加(あれば上書き)するためその階層より下に階層があっても消えてしまいます。指定した階層の値だけ書き換えるにはupdateChildrenメソッドを使用します。

updateChildrenメソッド

updateChildrenメソッドは任意の深さでメソッドを呼び出すことで引数に指定したMapの値に更新することができます。

val user = mapOf("username" to "test")
ref.child("users").updateChildren(user)

Mapに複数のキーと値のペアを保持させることで一度に複数箇所のデータを更新することも可能です。

val post = mapOf(
    "author" to "ame",
    "title" to "Test",
    "body" to "Message"
)
ref.child("users").updateChildren(post)

データの削除処理

データの削除処理removeValueメソッドを使用します。指定した値より子要素があった場合はその子要素も全て削除されます。

ref.child("users").removeValue()

また書き込み処理ができるsetValueupdateChildrenMapの値にnullを渡すことで削除することも可能です。その場合は一度に複数箇所のデータを削除することもできます。

成功/失敗リスナーを実装する

書き込みや削除などが成功したかどうかを取得したい場合はaddOnCompleteListener/addOnFailureListenerを使用します。

ref.child("users").setValue(null)
  .addOnCompleteListener {
      Log.d("Realtime Database", "書き込み成功")
  }.addOnFailureListener {
      Log.d("Realtime Database", "書き込み失敗")
  }

データの読み取り処理

データの読み取り処理はRealtime Databaseではサーバー側とローカルのキャッシュ側にデータを保持しているのでどちらのデータを読みに行くかを指定することができるようになっています。

以下のようなデータベースの中身の状態で読み取り処理を行なってみます。

【Swift UI/Firebase】Realtime Databaseの導入方法と使い方!

getメソッド

get1回だけデータを読み取るメソッドです。基本的にはサーバーの値を読みにいき、オフライン環境などによってサーバーの値の取得に失敗した場合はローカルキャッシュの値を読みにいきます。

実際の値を参照するにはaddOnSuccessListenerを使用します。引数ではDataSnapshot型のvalueプロパティで値を取得することができます。(スナップショットとは「その時点のもの」といった意味の英単語です)

エラーはaddOnFailureListenerでキャッチできます。

ref.child("users").get()
    .addOnSuccessListener {
        Log.d("Realtime Database", "取得した値: ${it.value}")
    }.addOnFailureListener{
        Log.d("Realtime Database", "エラー: ${it}")
    }

取得した値を扱いやすいようにMap型に変換するには以下のように実装します。

ref.child("users").get()
    .addOnSuccessListener {
        val result: Any? = it.value // nullの可能性もある
        if (result is Map<*, *>) {
            val map = result as Map <String, Any>
            Log.d("Realtime Database", "取得した値: $map")
        } else {
            Log.d("Realtime Database", "データが Map 型ではありません")
        }
    }.addOnFailureListener{
        Log.d("Realtime Database", "エラー: ${it}")
    }

addValueEventListenerメソッド

データベースに格納されているデータの変更を観測しつつデータを取得したい場合addValueEventListenerメソッドを使用します。このメソッドは初回の呼び出し時とサーバーの値が更新されたタイミングに実行されます。しかしツリー状のルートから呼び出すと全ての変更を観測することになるため、必要な深さまでを指定しアタッチするのが推奨されています。

addValueEventListenerメソッドにはValueEventListenerオブジェクトを渡します。オーバーライドしたonDataChangeからデータを参照でき、onCancelledでは観測をキャンセルされた際のエラーを取得できます。

val userListener = object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        val name = dataSnapshot.value
        Log.d("Realtime Database", "取得した値: $name")
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.d("Realtime Database", "キャンセル: ${databaseError.toException()}")
    }
}
ref.child("users").addValueEventListener(userListener)

観測を停止させる

観測を停止させたい場合removeEventListenerメソッドを使用します。引数にデタッチしたいリスナーオブジェクトを渡します。

ref.child("users").removeEventListener(userListener)

addListenerForSingleValueEventメソッド

ローカルのデータを明示的に取得したい場合addListenerForSingleValueEventを使用します。

val userListener = object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        val name = dataSnapshot.value
        Log.d("Realtime Database", "取得した値: $name")
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.d("Realtime Database", "キャンセル: ${databaseError.toException()}")
    }
}
ref.child("users").addListenerForSingleValueEvent(userListener)

オフライン環境でデータをキャッシュする

オフライン環境でもデータを永続的に表示できるようにするためには明示的に設定をする必要があります。

Firebase.database.setPersistenceEnabled(true)

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index