前回の連載では、
今回も、
していきたいと思います。
データの保存方法
Firebaeでデータを保存する方法は次の表にある4つです。
メソッド | 概要 |
---|---|
setValue() | 特定のURIにデータを直接保存 |
updateChildren() | 特定のデータの一部要素だけを更新 |
push() | リストに時系列にデータを追加 |
runTransaction() | 複雑なデータをアトミックに保存するためのトランザクション |
順番に確認していきましょう。
setValue()
setValue()
は最も基本的なデータの保存方法です。指定したURIにデータを直接書き込みます。すでに同一パスにデータが存在した場合はすべての情報を上書きします。
setValue()
には保存する任意のデータ型をそのまま指定できます。メッセージを表現するデータ型として以下のようなクラスを定義してください。
public class ChatMessage {
public String body;
public String sender;
public long timestamp;
public ChatMessage(String body, String sender, long timestamp) {
this.body = body;
this.sender = sender;
this.timestamp = timestamp;
}
}
あとはデータの読み出し同様、setValue()
メソッドを呼び出して書き込むだけです。
Firebase messages = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/messages");
message.child("01").setValue(new ChatMessage("How are you doing?", "Steve", System.currentTimeMillis()));
message.child("02").setValue(new ChatMessage("I'm great!", "Bill", System.currentTimeMillis()));
メッセージ一覧への参照を取得した後、child("01")
のようにして1つ目のメッセージを格納するためのキーを作り、
Webコンソールで確認して、

完了コールバック
もしsetValue()
で保存が完了したタイミングで何か処理を差し込みたい場合は、setValue()
の第2引数にFirebase.
を渡すことで完了後にコールバックしてもらえます。
messages.child("01").setValue(chatMessage, new Firebase.CompletionListener() {
@Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
Log.e(TAG, firebaseError.getMessage(), firebaseError.toException());
} else {
Log.d(TAG, "data successfully saved!");
}
}
});
エラー発生時にはFirebaseError
が渡されるので、
以下のようにログに出力されれば成功です。
D/Firebase: data successfully saved!
updateChildren()
先ほどのsetValue()
で大抵の場合は問題ないのですが、setValue()
は向きません。setValue()
は毎回すべての情報をまるごと書き換えてしまうからです。
このような用途にはupdateChildren()
を利用します。
Map<String, Object> sender = new HashMap<>();
sender.put("sender", "Woz");
messages.child("01").updateChildren(sender);
このようにすると、sender
だけをSteve
からWoz
に書き換えることができます。body
とtimestamp
はノータッチなので効率的です。
push()
メッセージ一覧のようなデータを作成するとき常に意識しておかなければならないことは、
最初にsetValue()
で例示したような、/messages/
,messages/
のように連番を手動で追加するようなコードでは、push()
メソッドです。
push()
メソッドを呼び出すと、
IDはランダムな文字列ですが、
messages.push().setValue(new ChatMessage("I can't hear you!", "Hartman", System.currentTimeMillis()));
messages.push().setValue(new ChatMessage("Sir, yes sir!", "Lawrence", System.currentTimeMillis()));
この通り、setValue()
の間にpush()
と挟むだけで簡単に利用できます。
Webコンソールで確認して、

もし別の場所で参照するためにこの一意なIDが必要な場合は、
Firebase newPostRef = messages.push();
newPostRef.setValue(new ChatMessage("Is this me?", "Joker", System.currentTimeMillis()));
String key = newPostRef.getKey();
Log.d(TAG, "key: " + key);
ログに以下のように出力されれば成功です。
D/Firebase: key: -KGD-cmiz_I0ZKOC_Fx8
runTransaction()
先ほども申し上げたように、
たとえば、
FirebaseではrunTransaction()
メソッドで簡単にトランザクション処理を行うことができます。
まずはコードを見て下さい。それから順に解説していきます。
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/counter");
ref.runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
if (mutableData.getValue() == null) {
mutableData.setValue(1);
} else {
Long counter = mutableData.getValue(Long.class);
counter++;
mutableData.setValue(counter);
}
return Transaction.success(mutableData);
}
@Override
public void onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot dataSnapshot) {
if (committed) {
String logMessage = dataSnapshot.getValue().toString();
Log.d(TAG, "counter: " + logMessage);
} else {
Log.e(TAG, firebaseError.getMessage(), firebaseError.toException());
}
}
});
まず、runTransaction()
メソッドを呼び出します。
runTransaction()
にはTransaction.
インスタンスを引数として渡します。
前半のpublic Transaction.
の部分が、public void onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot dataSnapshot) { }
の部分がトランザクション完了後の処理を記述する部分になります。
doTransaction()
に渡されるMutableData
は、null
チェックし、
既に値がある場合はMutableData#getValue()
でそれを取り出すことができます。ここではクラス型を指定して型安全に取得可能です。今回の例ではカウンターなので整数型で取り出しています。
最後にTransaction.
で成功のトランザクションとして次の処理に結果を渡しています。
onComplete(FirebaseError firebaseError, boolean committed, DataSnapshot dataSnapshot)
では、
すべての処理が完了すると、
D/Firebase: counter: 12
オフライン時の挙動
前回でも少し触れましたが、
もし、
このことで、
- 「もしオフラインならばダイアログを表示してユーザを待たせて…」
- 「もしネットワークが回復したらリトライ処理をして…」
といった複雑な処理を記述する必要がなく、
まとめ
今回までの連載で、
さて、