🍣
[Android Studio] Firebase RealtimeDatabaseをつかってみた
はじめに
firebase初心者である私が公式のサンプルを見つつ、データベースへ書き込みおよび読み取りをしてみたので残しときます。。(多分見る人が見れば公式だけでも事足りると思いますけど、私はわからなかったので書きます)
では、いくぜい!!
基本的には以下、4つのクラスを実装して実行すればOK
Post.java
import com.google.firebase.database.Exclude;
import com.google.firebase.database.IgnoreExtraProperties;
import java.util.HashMap;
import java.util.Map;
@IgnoreExtraProperties
public class Post {
public String uid;
public String author;
public String title;
public String body;
public int starCount = 0;
public Map<String, Boolean> stars = new HashMap<>();
public Post() {
// Default constructor required for calls to DataSnapshot.getValue(Post.class)
}
public Post(String uid, String author, String title, String body) {
this.uid = uid;
this.author = author;
this.title = title;
this.body = body;
}
@Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("author", author);
result.put("title", title);
result.put("body", body);
result.put("starCount", starCount);
result.put("stars", stars);
return result;
}
}
User.java
import com.google.firebase.database.IgnoreExtraProperties;
@IgnoreExtraProperties
public class User {
public String username;
public String email;
public User() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public User(String username, String email) {
this.username = username;
this.email = email;
}
}
ReadAndWriteSnippets.java
package test.com.test_firebase.RealtimeDatabase;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.MutableData;
import com.google.firebase.database.ServerValue;
import com.google.firebase.database.Transaction;
import com.google.firebase.database.ValueEventListener;
import java.util.HashMap;
import java.util.Map;
public class ReadAndWriteSnippets {
private static final String TAG = "ReadAndWriteSnippets";
// データベースでデータの読み書きを行うために使用
private DatabaseReference mDatabase;
// コンストラクタ
public ReadAndWriteSnippets() {
mDatabase = FirebaseDatabase.getInstance().getReference();
}
public void writeNewUser(String userId, String name, String email) {
User user = new User(name, email);
// 情報をDatabaseに設定
// この方法では、特定の場所にあるデータ(子ノードも含む)が上書きされる
mDatabase.child("users").child(userId).setValue(user);
// この方法では、オブジェクト全体を書き換えずに子を更新することもできる。
// mDatabase.child("users").child(userId).child("username").setValue(name);
addPostEventListener(mDatabase);
}
// パスにあるデータを読み取って、変更をリッスンするには、addValueEventListener() メソッドを使用して
// ValueEventListener を DatabaseReference に追加します。
public void addPostEventListener(DatabaseReference mPostReference) {
ValueEventListener postListener = new ValueEventListener() {
@Override // 特定のパスにあるコンテンツの静的スナップショットを、イベントの発生時に存在していたとおりに読み取ることができる
// Listenerがアタッチされたときに1回、また、データ(子も含む)が変更されるたびにコールされる
/**
* @param dataSnapshot:その場所にあるすべてのデータ(子のデータも含む)を含んでいるスナップショット
*/
public void onDataChange(DataSnapshot dataSnapshot) {
/**
* Snapshot.getValue():そのデータの Java オブジェクト表現が返され、その場所にデータが存在しない場合、null が返される。
*/
Post post = dataSnapshot.getValue(Post.class);
// realtime databaseから情報を読み取る
String email = (String)dataSnapshot.child("users").child("1").child("email").getValue();
String username = (String)dataSnapshot.child("users").child("1").child("username").getValue();
Log.i(TAG, "email:" + email);
Log.i(TAG, "username:" + username);
}
@Override // 読み取りがキャンセルされた場合に呼び出される
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
};
mPostReference.addValueEventListener(postListener);
}
// データベースから一度だけ情報を読み取る
public void getSnapshot(String userId) {
mDatabase.child("users").child(userId).get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
@Override
public void onComplete(@NonNull Task<DataSnapshot> task) {
if (!task.isSuccessful()) {
Log.e("firebase", "Error getting data", task.getException());
}
else {
Log.d("firebase", String.valueOf(task.getResult().getValue()));
}
}
});
}
// 投稿を作成して、それと同時にその投稿から最近のアクティビティ フィードと投稿ユーザーのアクティビティ フィードを更新する
private void writeNewPost(String userId, String username, String title, String body) {
// Create new post at /user-posts/$userid/$postid and at /posts/$postid simultaneously
// push() を使用して、/posts/$postid にある全ユーザーの投稿が格納されているノード内に投稿を作成すると同時に、
// getKey() でキーを取得しています。
String key = mDatabase.child("posts").push().getKey();
Post post = new Post(userId, username, title, body);
Map<String, Object> postValues = post.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + userId + "/" + key, postValues);
// 他の子ノードを上書きすることなく、ノードの特定の複数の子に同時に書き込む
// updateChildren() を 1 回呼び出すだけで JSON ツリー内の複数の場所に対して更新を同時に実行できる。
mDatabase.updateChildren(childUpdates);
}
private String getUid() {
return "";
}
private void onStarClicked(DatabaseReference postRef) {
postRef.runTransaction(new Transaction.Handler() {
@Override // 投稿にスターを付ける/スターを外すユーザーのIDと、インクリメントされたスターの数をデータベースに書き込む。
public Transaction.Result doTransaction(MutableData mutableData) {
Post p = mutableData.getValue(Post.class);
if (p == null) {
return Transaction.success(mutableData);
}
if (p.stars.containsKey(getUid())) {
// Unstar the post and remove self from stars
// 投稿のスターを取り消す操作
p.starCount = p.starCount - 1;
p.stars.remove(getUid());
} else {
// Star the post and add self to stars
// 投稿にスターを付ける操作
p.starCount = p.starCount + 1;
p.stars.put(getUid(), true);
}
// Set value and report transaction success
mutableData.setValue(p);
return Transaction.success(mutableData);
}
@Override
public void onComplete(DatabaseError databaseError, boolean committed,
DataSnapshot currentData) {
// Transaction completed
Log.d(TAG, "postTransaction:onComplete:" + databaseError);
}
});
}
// ユーザーが投稿にスターを付けていることがわかっている場合は、
// トランザクションではなくアトミックなインクリメント オペレーションを使用できます。
private void onStarClicked(String uid, String key) {
Map<String, Object> updates = new HashMap<>();
updates.put("posts/"+key+"/stars/"+uid, true);
updates.put("posts/"+key+"/starCount", ServerValue.increment(1));
updates.put("user-posts/"+uid+"/"+key+"/stars/"+uid, true);
updates.put("user-posts/"+uid+"/"+key+"/starCount", ServerValue.increment(1));
mDatabase.updateChildren(updates);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ReadAndWriteSnippets readAndWriteSnippets = new ReadAndWriteSnippets();
readAndWriteSnippets.writeNewUser("1", "Jack", "jack@gmail.com");
}
}
ReadAndWriteSnippetsクラスではほかに、DBから値を1度だけ取得することが出来るgetSnapshot()や投稿の作成及びアクティビティの取得を行うwriteNewPost()、投稿にスターを取り付けるonStartClicked()などが用意されている。
Discussion