スマホアプリ開発を加速する、Firebaseを使ってみよう

第2回Firebase最初の一歩 ─簡単なデータの保存と読み出し

前回の連載では、Firebaseとはどんなもので何ができるかを簡単に見てきました。今回は実際にFirebaseにサインアップし、データの読み書きを行ってみたいと思います。

今回の連載では、例として「ユーザ一覧」を作成し、以下のようなユーザを保存して読み出してみたいと思います。

  • usersというユーザ一覧がある
  • usersの中にshiroyamaという一意に識別可能なユーザがいる
  • shiroyamanameaddressという属性を持っており、それぞれ詳細名と住所を表している

このようなデータ構造をFirebaseではどのように扱うのか、注目しておいてください。

Firebaseにサインアップ

Firebaseは、Googleアカウントをお持ちの方は誰でもすぐにサインアップして無料で使い始めることができます(無料プランの制限や有料プランについては後の連載でご紹介します⁠⁠。

Firebase公式サイトのトップページにアクセスし、画面右上のSIGN UP WITH GOOGLEをクリックしてください。

図1 SIGN UP WITH GOOGLEボタン
図1 SIGN UP WITH GOOGLEボタン

お使いのGoogleアカウントを選択してください。

図2 アカウントの選択
図2 アカウントの選択

FirebaseにGoogleアカウント情報の利用を許可してください。

図3 アカウント利用リクエストを許可
図3 アカウント利用リクエストを許可

しばらく待つと、Firebaseへのサインアップが完了し、ダッシュボードが表示されます。

図4 ダッシュボード
図4 ダッシュボード

また、サインアップと同時に「MY FIRST APP」というアプリケーションが自動生成されます。

アプリケーションという言葉に違和感を覚えるかもわかりませんが、この中に

  • データベースと利用するデータすべて
  • アクセス制御
  • 認証機構
  • 静的Webホスティング

等が内包されています。差し当たっては、⁠アプリケーション=データベース」と理解していただいて問題ありません。

図5 ⁠MY FIRST APP」
図5 「MY FIRST APP」

アプリケーションはhttps://<YOUR-FIREBASE-APP>.firebaseio.com/ 」という形式で、<YOUR-FIREBASE-APP>の部分はアプリケーションごとに一意となります。以下、<YOUR-FIREBASE-APP>の部分はご自身の環境に表示されている表記で読み替えてください。

WebブラウザにこのURIを入力するか、画面の「Manage App」をクリックするとアプリケーションのWebコンソールに移動することができます。このアプリケーションおよびWebコンソールの詳しい使い方は後述しますが、ここではアプリケーションが一意なURIを持つことを覚えておいてください。

以上でFirebaseへのサインアップは完了です。5分もかからなかったのではないでしょうか?

Firebaseのデータ構造

Firebaseに実際にデータを保存したり読み出したりする前に、Firebaseのデータ構造について理解しておくことはとても重要です。

JSONオブジェクト

Firebaseのデータはアプリケーションごとに1つのJSONオブジェクトとして保存されます。つまり、リレーショナルデータベースにあるテーブルやスキーマ、それに対応するレコードといったものは存在しません。

いわゆるドキュメント志向なNoSQLとして、JSONで表現できる任意の柔軟なデータ構造を取ることができます。

冒頭で申し上げたユーザ一覧の例は、Firebaseでは以下のように表現することができます。

{
  "users" : {
    "shiroyama" : {
      "name" : "Fumihiko Shiroyama",
      "address" : "Tokyo, JP"
    },
    "satou" : { ... },
    "suzuki" : { ... },
    "tanaka" : { ... }
  }
}

スキーマレスなので、後からユーザの属性に"gender" : "male"を追加するといったことも容易にできます。

{
  "users" : {
    "shiroyama" : {
      "name" : "Fumihiko Shiroyama",
      "address" : "Tokyo, JP",
      "gender" : "male"
    },
    ...
  }
}

データをURIで一意に特定

JSONオブジェクトということは、データがツリー状に階層化されているということなので、あるアプリケーションのあるデータをURIで簡単に特定することができます。先ほどの例で言うと、https://<YOUR-FIREBASE-APP>.firebaseio.com/users/shiroyama/nameにアクセスするとFumihiko Shiroyamaというデータを取り出すことができます。

これは、リレーショナルデータベース等よりもデータの構造が直感的にわかりやすく、また、特定の階層にだけアクセス制御を掛けるといったことも容易なので、Firebaseの利点のひとつと言えるでしょう。

Webコンソールでデータを保存

Firebaseのデータの構造について理解したところで、さっそくWebコンソールを使ってデータを保存してみましょう。

ダッシュボードにアクセスし、サインアップ時に自動生成されたアプリケーションの「Manage App」をクリックすると、初回アクセス時にはデータの読み書きのチュートリアルを体験することができます。

図6 Firebase Tour
図6 Firebase Tour

「Take the tour」をクリックすると、⁠+」アイコンを押してnamevalueに何か書き込んでみるように促されます。

ユーザ一覧を作成する前に、Webコンソールに慣れるために、ここではnamemessagevalueHello Firebaseとシンプルな文字列を保存してみましょう。

図7 Add Data
図7 Add Data

「Add」を押してデータが保存されるのを確認してみてください。

図8 Data Added
図8 Data Added

Webコンソールの使い方がわかったところで、ユーザ一覧を作成してみたいと思います。

先ほどデータを保存する際に指定したvalueには、文字列や整数といったシンプルな値のみならず、直接JSONオブジェクトを記述することもできます。今回はnameusersvalue{"shiroyama":{"name":""}}を保存してみてください。

Webコンソールにいきなり複雑なJSONオブジェクトを記述するのは大変なので、あえて{"name":""}と空欄にしてあります。

図9 Add Object[1]
図9 Add Object[1]

JSONオブジェクトとして保存されていることが確認できると思います。

図10 Add Object[2]
図10 Add Object[2]

次に{"name":""}の空欄の部分にカーソルを合わせてクリックすると、直接そのフィールドを加筆/修正することができます。

図11 Add Object[3]
図11 Add Object[3]

次にaddressの属性を追加してみたいと思います。shiroyamaの右あたりにカーソルを合わせて「+」アイコンをクリックしてください。

図12 Add Object[4]
図12 Add Object[4]

nameaddressvalueTokyo, JPと入力して「Add」で保存してください。

図13 Add Object[5]
図13 Add Object[5]

これでユーザ一覧usersshiroyamaというJSONオブジェクトを作成することができました。

図14 Add Object[6]
図14 Add Object[6]

実際にはこのWebコンソールでこのような複雑なデータを保存する機会はそれほど多くはありませんが、Firebaseでデータがどのように保持されているか視覚的に確認できたのではないでしょうか。

Androidクライアントからデータを読み出し

さて、いよいよFirebaseに保存したデータを読み出してみたいと思います。

Firebaseのデータを読み書きできるクライアントにはWeb、iOS、Android、REST等がありますが、ここではAndroidクライアントの例を紹介します。

セットアップ方法こそ各クライアントで違いますが、その後の読み出し方や概念等はほとんど同じと言って差し支えありませんので、Android以外のクライアントをご利用予定の方も是非読み進めていただければ幸いです。

Androidクライアントのセットアップ

Android用のFirebaseクライアントライブラリはMaven Centralレポジトリに提供されているので、Gradleで簡単に導入することができます。

Android Studioの場合はbuild.gradleに以下を追加してください。

dependencies {
    compile 'com.firebase:firebase-client-android:2.5.2+'
}

もしビルド時にDuplicate files copied in APK META-INF/NOTICE...等のエラーが出てビルドに失敗する場合はbuild.gradleに以下を追加してください。

android {
    ...
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE-FIREBASE.txt'
        exclude 'META-INF/NOTICE'
    }
}

Firebaseはインターネットに接続するのでAndroidManifest.xmlandroid.permission.INTERNETパーミッションを追加してください。

<uses-permission android:name="android.permission.INTERNET" />

最後に、Firebaseの初期化処理を自前のApplicationクラスに定義します。

android.app.Applicationを継承したクラスを定義し、以下のようにFirebase.setAndroidContext(this);を記述してください。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Firebase.setAndroidContext(this);
    }
}

独自Applicationクラスを定義したので、Androidアプリケーションがそれを参照するようにAndroidManifest.xmlapplicationタグにandroid:name属性を追加してください。

<application
  android:name=".MyApplication"
  ...>
</application>

以上でFirebaseのAndroidクライアントライブラリを使用する準備は整いました。

データを読み出し

それではデータを読み出してみましょう。

ここでは先ほどWebコンソールから追加した以下のデータが既にFirebase上に格納されている前提で、/users/shiroyama/nameに存在する値を読み出してみたいと思います。

{
  "users" : {
    "shiroyama" : {
      "name" : "Fumihiko Shiroyama",
      "address" : "Tokyo, JP"
    }
  }
}

データを読み出したい任意の場所(たとえばActivity#onCreate()内)で以下のようなコードを記述してみてください。前述のとおり<YOUR-FIREBASE-APP>の部分はお使いの環境で読み替えてください。

Firebase firebaseRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");

firebaseRef.child("users/shiroyama/name").addValueEventListener(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // "Fumihiko Shiroyama"
    Log.d("Firebase", snapshot.getValue().toString());
  }
  @Override public void onCancelled(FirebaseError error) { }
});

実行してログにD/Firebase: Fumihiko Shiroyamaと表示されれば成功です。

イベント駆動プログラミング

コードの解説をする前に、ここで興味深い実験をしてみましょう。Webコンソールで先程の"name" : "Fumihiko Shiroyama""name" : "John Smith"に変更してみてください。すると、Android側のコードは一行も変更せず、アプリをリビルドしたり再起動したりしなくても、

D/Firebase: John Smith

とログに表示されませんでしたか?

実はここで書いたコードは、利用者が能動的にデータを取得する「Pull型」の取得方法ではなく、データが追加/変更されたタイミングで通知される「Push型」の取得方法だったのです。このようなプログラミングパラダイムは「イベンド駆動プログラミング」と呼ばれ、Firebaseを利用したプログラミングの大きな特徴のひとつとなっています。

プログラマはその時々で欲しいデータを要求するのではなく、⁠こういう状況ではデータをこうしたい」という処理(コールバック関数やリスナと呼称されます)をあらかじめ登録しておくことで、将来の任意のタイミングで起こる追加や変更にリアルタイムに応答するリッチな体験をユーザに提供することができるのです。

コードの解説

Firebaseのプログラミングの特徴がわかったところで、先ほどのコードを詳しく見ていきましょう。

まず、1行目のFirebase firebaseRef = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");の部分に注目してください。これはFirebaseの「reference(参照⁠⁠」と呼ばれ、これから読み書きするFirebase上のデータの場所を指し示しています。この例では、https://<YOUR-FIREBASE-APP>.firebaseio.com/だけ指定しているので、当該データベースのルート、つまりJSONツリーの1番てっぺんを指しています。

注意点として、この参照を作った時点ではいかなるデータの読み書きも発生していません。あくまでその位置を指し示しただけに過ぎません。

次に、2行目のfirebaseRef.child("users/shiroyama/name")の部分に着目してください。これは、先ほど作った参照の子ノードusers/shiroyama/nameを参照すると指定しています。つまりhttps://<YOUR-FIREBASE-APP>.firebaseio.com/users/shiroyama/nameに対してこれから読み書きをすると指定していることになります。

最後に、2~最終行のaddValueEventListener(new ValueEventListener() { })の部分に注目してください。ここでは「データが新しく追加されたり変更された場合に処理する内容(リスナ⁠⁠」を登録しています。データが追加されたらonDataChange(DataSnapshot snapshot){ }が呼ばれるというわけです。

では、DataSnapshotとは何なのでしょうか? また、データが追加/変更される以外にもイベントが追加されるタイミングはあるのでしょうか? このあたりは、次回で詳しく掘り下げていきたいと思います。

まとめ

今回は、Firebaseにサインアップし、Webコンソールでデータを保存し、Androidからそのデータを読み出す部分までを駆け足で見てきました。次回は、Firebaseからデータを読み出す方法についてより詳しく解説したいと思います。お楽しみに。

おすすめ記事

記事・ニュース一覧