FirebaseのRealtime Databaseの設定から簡単なデータ入力まで(Androidアプリ)

##概要

<font color="RED">Firebaseのアカウントがあることが前提です。</font>
Firebase Realtime Databaseの公式解説は[こちら](https://firebase.google.com/docs/database/)。
簡単に説明すると、リアルタイム更新に特化した簡易データベースで、チャットなど雑多なことに使うことが多いようです。

##Realtime Databaseの始め方
Android Studioの上のメニューにあるTools → Firebaseを選択。
Assistantが表示されるのでRealtime Databaseを選択。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/252283/5e3a1262-3d15-ea51-84fe-1d0f65a4159c.png)

セットアップ方法が書かれたリンクが表示されます。
[スタートガイド](https://firebase.google.com/docs/database/android/start/)
これを読まなくても番号付きで手順が書いてあり、
ボタンをクリックしていくだけで、以前は設定できました。
（結果としては今回は苦戦しました・・・）
![2.png](https://qiita-image-store.s3.amazonaws.com/0/252283/06842771-6fee-6cf5-e8be-76736f1708aa.png)

##Realtime Databaseの設定
###①Connected your app to Firebase
[Connected to Firebase]をクリックするとGoogleアカウントの選択画面が表示され、認証を許可すると自動的にFirebaseにプロジェクトを作成、リンクしてくれます。
Firebaseにアクセスすると、プロジェクトが見えるはずです。

###②Add the Realtime Database to your app
[Add the Realtime Database to your app]をクリックすると以下を自動で追加してくれます。

```gradle:build.gradle(project-level)
// Add Firebase Gradle buildscript dependency
classpath 'com.google.gms:google-services:4.0.1'
```

```gradle:app/build.gradle
// Add Firebase plugin for Gradle
apply plugin: 'com.google.gms.google-services'

// build.gradle will include these new dependencies:
compile 'com.google.firebase:firebase-database:16.0.1:15.0.0'
```

この状態でビルドすると、なぜかコンパイルが通らない。
implementation 'com.android.support:appcompat-v7:27.1.1'
の赤線のエラー内容を見ると

 \----------------------------------
*All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.1.1, 26.1.0. Examples include com.android.support:animated-vector-drawable:27.1.1 and com.android.support:support-media-compat:26.1.0 less... (Ctrl+F1)
There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion).  Issue id: GradleCompatible*
\----------------------------------
implementation 'com.android.support:appcompat-v7:27.1.1'
と
implementation 'com.google.firebase:firebase-database:16.0.1:15.0.0'
の内部で別バージョンの同一ライブラリが見つかったとのこと。

firebase-databaseのほうが古いライブラリを含んでいるので最新を探し入れてみても、同じ結果でした。
（参照）[Firebase Android Release Note](https://firebase.google.com/support/release-notes/android)
Realtime Database     com.google.firebase:firebase-database:16.0.3

仕方がなくappcompatのほうを切り替え。
implementation 'com.android.support:appcompat-v7:27.1.1'
↓
implementation 'com.android.support:appcompat-v7:26.1.0'
compileSdkVersionとtargetSdkVersionを26に変更。

そうすると次のエラー
 \----------------------------------
Could not find firebase-database-15.0.0.jar (com.google.firebase:firebase-database:16.0.1).
 \----------------------------------
こんなjava Archiveはないとのこと、自動に追加しておいてどういうことかと思いながらも、
[スタートガイド](https://firebase.google.com/docs/database/android/start/)
を読むと

```gradle:app/build.gradle
implementation 'com.google.firebase:firebase-database:16.0.3'
```
と、最新のにしてとのこと。

そうすると

```gradle:app/build.gradle
implementation 'com.google.firebase:firebase-core:16.0.4'
```

も入れてとWarningが出るので従う。
ここら辺の内部ライブラリバージョンが違う問題はもうすぐ改善されるということをGoogleの開発者ブログに書いてあったような。

###③Configure Firebase Database Rules
認証についてのリンクとDBの作成ルールのリンクがあります。
[Firebase Authentication](https://firebase.google.com/docs/auth/?utm_source=studio)
[データベース ルールを使ってみる](https://firebase.google.com/docs/database/security/quickstart)

認証については、ユーザーの個人情報など機密性の高いものにする場合に必要です。
簡易的なチャットやゲームランキングなどでは使う必要はないと思います。（たぶん）

では、ブラウザでFirebaseのコンソールにアクセスして、左タブのDatabaseをクリック。
データベースの作成をクリック。
テストモードで作成。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/252283/0ef2a6fb-48dd-edae-d5bd-e3c5a1072eb2.png)
するとタブがCloud Firestore[ベータ版]になっているので、
Realtime Databaseにしてください。
![4.png](https://qiita-image-store.s3.amazonaws.com/0/252283/c28e9337-2148-9eb7-3c75-be356458e00e.png)


とにかくDBのルール作成の癖がすごいので、作成が難しくなっています。
リレーショナルDBのような設計はできません。
細かいルールについては以下のリンクを参照してください。

---------------------------------------------------------
〇Androidについて
・ガイド
[スタートガイド](https://firebase.google.com/docs/database/android/start/)
[データベースの構造化](https://firebase.google.com/docs/database/android/structure-data)
[Android でのデータの読み取りと書き込み](https://firebase.google.com/docs/database/android/read-and-write)
[Android 上でのデータのリストの操作](https://firebase.google.com/docs/database/android/lists-of-data)
[Android でのオフライン機能の有効化](https://firebase.google.com/docs/database/android/offline-capabilities)

・リファレンス
[パッケージサマリー](https://firebase.google.com/docs/reference/android/com/google/firebase/database/package-summary)

〇セキュリティとルールについて
・ガイド
[Firebase Realtime Database ルールについて](https://firebase.google.com/docs/database/security/)
[データベース ルールを使ってみる](https://firebase.google.com/docs/database/security/quickstart)
[データのセキュリティ保護](https://firebase.google.com/docs/database/security/securing-data)
[ユーザーベースのセキュリティ](https://firebase.google.com/docs/database/security/user-security)
[非安全性を解決する](https://firebase.google.com/docs/database/security/resolve-insecurities)
[データのインデックス作成](https://firebase.google.com/docs/database/security/indexing-data)
[REST で Firebase Realtime Database ルールを管理する](https://firebase.google.com/docs/database/rest/app-management)

・リファレンス
[Firebase Database Security Rules API](https://firebase.google.com/docs/reference/security/database/)
[Firebase Security Rules Regular Expressions](https://firebase.google.com/docs/reference/security/database/regex)
[Firebase Security Rules for Cloud Storage Reference](https://firebase.google.com/docs/reference/security/storage/)

---------------------------------------------------------

とりあえず簡単なルールを作成

```json:ルール
{
  /* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
  "rules": {
    "info":{
      "user": {
        ".read": true,
        ".write": true,
        "name": {
          ".validate": "newData.isString()"
        },
        "age": {
          ".validate": "newData.isNumber()"
        }
      }
    }
  }
}
```

infoの下にuser、その下にname(String型),age(Number型)を作成しただけのルールです。
階層を深くしたのは、パスの指定ルールをわかりやすくするためです。

###④Write to your database
早速データを書き込んでみます。
[Android でのデータの読み取りと書き込み](https://firebase.google.com/docs/database/android/read-and-write)
がわかりやすいです。
データを個別に登録することも可能ですが、かなり面倒な作りになるので、クラス単位での登録、取得のほうが楽です。

**〇クラスの作成**
`（注意）そのオブジェクトを定義するクラスに、引数を取らないデフォルト コンストラクタと、代入するプロパティのパブリック ゲッターが存在することが条件です。`


```java:User 
public static class User {
    public String name;
    public Integer age;

    // 空のコンストラクタの宣言が必須
    public User() {
    }

    public User(String _name, Integer _age) {
        name = _name;
        age = _age;
    }
    public String getName(){
        return name;
    }
    public Integer getAge(){
        return age;
    }
}
```
**〇データ登録**

```java:register
User user = new User( "山田太郎",30 );
// インスタンスの取得
FirebaseDatabase database = FirebaseDatabase.getInstance();

// ファイルパスを指定してリファレンスを取得
DatabaseReference refName = database.getReference("info/user");
// データを登録
refName.setValue(user);
```

Firebaseのデータを見てみると
![5.png](https://qiita-image-store.s3.amazonaws.com/0/252283/73093a9d-9552-9fc7-a291-2f6aa893e216.png)

しっかり登録されてますね。

###⑤Read from your database
データの読み取りを行います。
[Android でのデータの読み取りと書き込み](https://firebase.google.com/docs/database/android/read-and-write)
よりも
ガイド→管理→[データを取得する](https://firebase.google.com/docs/database/admin/retrieve-data?hl=ja)
のほうがわかりやすいかもしれません。
ドキュメントの例文がとっ散らかっていてわかりづらい・・・

簡単に書くとイベントリスナーをセットすることで、全取得や更新取得などができるということです。
とりあえず全取得だけ記載。

**〇データ取得**

```java:reader
// インスタンスの取得
FirebaseDatabase database = FirebaseDatabase.getInstance();
// ファイルパスを指定してリファレンスを取得
final DatabaseReference refUser = database.getReference("info");
refUser.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {

        User user = dataSnapshot.getValue(User.class);
        Log.w( "DEBUG_DATA", "user.name = " + user.name);
        Log.w( "DEBUG_DATA", "user.age = " + user.age);
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String s) {
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
    }
});
```

###⑥Optional: Configure ProGuard
プロガードを設定する場合は気を付けてねって内容。
使ってないので割愛・・・

*When using Firebase Realtime Database in your app along with ProGuard you need to consider how your model objects will be serialized and deserialized after obfuscation. If you use DataSnapshot.getValue(Class) or DatabaseReference.setValue(Object) to read and write data you will need to add rules to the proguard-rules.pro file:*

\-----
\# Add this global rule
-keepattributes Signature

\# This rule will properly ProGuard all the model classes in
\# the package com.yourcompany.models. Modify to fit the structure
\# of your app.
-keepclassmembers class com.yourcompany.models.** {
  *;
}
\-----

###⑦Preapre for Launch
[チェックリスト](https://firebase.google.com/support/guides/launch-checklist?utm_source=studio)でチェックしてねという内容。
大したことはない。

###⑧Next Steps
複数のデータベースを利用することもできますよ、という内容。
[複数のデータベースでスケールする](https://firebase.google.com/docs/database/usage/sharding?utm_source=studio)
メルカリは相当な数のデータベースを結び付けて膨大な量のチャットを実現していると聞いたことがあるような。
本当にサーバーレスな時代ですね。

基本編だけで長くなってしまいました。
このままではただ単に簡単なデータを入力、取得しただけになっていて、使い道がなさそうです。
応用編は後程。