[開示:私はFirebaseのエンジニアです。この質問は、一度に多くの質問に回答するための参照用の質問です。]
Firebaseデータベースには次のJSON構造があります。
{
"users": {
"-Jx5vuRqItEF-7kAgVWy": {
"handle": "puf",
"name": "Frank van Puffelen",
"soId": 209103
},
"-Jx5w3IOHD2kRFFgkMbh": {
"handle": "kato",
"name": "Kato Wulf",
"soId": 394010
},
"-Jx5x1VWs08Zc5S-0U4p": {
"handle": "mimming",
"name": "Jenny Tong",
"soId": 839465
}
}
}
私はこれを次のコードで読んでいます:
private static class User {
String handle;
String name;
public String getHandle() { return handle; }
public String getName() { return name; }
}
Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/32108969/users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot usersSnapshot) {
for (DataSnapshot userSnapshot : usersSnapshot.getChildren()) {
User user = userSnapshot.getValue(User.class);
System.out.println(user.toString());
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
しかし、私はこのエラーを受け取ります:
スレッド "FirebaseEventTarget"の例外com.firebase.client.FirebaseException:タイプへのバウンスに失敗しました
ユーザーをJavaオブジェクトに読み込むにはどうすればよいですか?
FirebaseはJacksonを使用してJavaオブジェクトをJSONにシリアル化し、JSONをJavaオブジェクトに逆シリアル化します。Jacksonの詳細については ジャクソンのウェブサイト およびこれ ジャクソンの注釈に関するページ 。
この回答の残りの部分では、FirebaseでJacksonを使用する一般的な方法をいくつか示します。
FirebaseからユーザーをAndroidに読み込む最も簡単な方法は、JSONのプロパティを完全に模倣するJavaクラスを作成する場合です。
_private static class User {
String handle;
String name;
long stackId;
public String getHandle() { return handle; }
public String getName() { return name; }
public long getStackId() { return stackId; }
@Override
public String toString() { return "User{handle='"+handle+“', name='"+name+"', stackId="+stackId+"\’}”; }
}
_
このクラスをリスナーで使用できます。
_Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/32108969/users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot usersSnapshot) {
for (DataSnapshot userSnapshot : usersSnapshot.getChildren()) {
User user = userSnapshot.getValue(User.class);
System.out.println(user.toString());
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
_
Userクラスは JavaBeanプロパティパターン に従うことに注意してください。すべてのJSONプロパティはUserクラスのフィールドによってマッピングされ、各フィールドにパブリックgetterメソッドがあります。すべてのプロパティが正確に同じ名前でマップされるようにすることで、Jacksonがそれらを自動的にマップできるようにします。
また、Javaクラス、およびそのフィールドとメソッドにJacksonアノテーションを配置することにより、マッピングを手動で制御することもできます。最も一般的な2つのアノテーション(_@JsonIgnore
_および_@JsonIgnoreProperties
_)以下。
ユーザーの名前とJavaコードで処理するだけです。stackId
を削除して何が起こるか見てみましょう。
_private static class User {
String handle;
String name;
public String getHandle() { return handle; }
public String getName() { return name; }
@Override
public String toString() {
return "User{handle='" + handle + “\', name='" + name + "\’}”;
}
}
_
前と同じリスナーをアタッチしてプログラムを実行すると、例外がスローされます。
_Exception in thread "FirebaseEventTarget" com.firebase.client.FirebaseException: Failed to bounce to type
at com.firebase.client.DataSnapshot.getValue(DataSnapshot.Java:187)
at com.firebase.LoadPartialUsers$1.onDataChange(LoadPartialUsers.Java:16)
_
「デバウンスに失敗したタイプ」は、JacksonがJSONをユーザーオブジェクトにデシリアライズできなかったことを示します。ネストされた例外では、次の理由がわかります。
_Caused by: com.shaded.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "stackId" (class com.firebase.LoadPartialUsers$User), not marked as ignorable (2 known properties: , "handle", "name"])
at [Source: Java.io.StringReader@43079089; line: 1, column: 15] (through reference chain: com.firebase.User["stackId"])
at com.shaded.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.Java:79)
_
ジャクソンはJSONでプロパティstackId
を見つけましたが、それをどう処理するかわからないため、例外をスローします。幸いなことに、User
クラスにマッピングするときにJSONの特定のプロパティを無視するように指示するために使用できる注釈があります。
_@JsonIgnoreProperties({ “stackId" })
private static class User {
...
}
_
リスナーを使用してコードを再度実行しない場合、JacksonはJSONのstackId
を無視できることを認識し、JSONをユーザーオブジェクトにデシリアライズできるようになります。
Firebaseアプリケーションでは、プロパティをJSONに追加するのが一般的であるため、Javaクラスにマッピングのないすべてのプロパティを無視するようにジャクソンに指示する方が便利な場合があります。
_@JsonIgnoreProperties(ignoreUnknown=true)
private static class User {
...
}
_
後でJSONにプロパティを追加した場合、JavaコードはUser
sをロードできます。ユーザーオブジェクトにはすべての情報が含まれないことに注意してください。 JSONに存在していたので、Firebaseに再度書き込む際には注意してください。
カスタムのJavaクラスを用意するのが良い理由の1つは、便利なメソッドを追加できることです。ユーザーに表示する名前を取得する便利なメソッドを追加するとします。
_private static class User {
String handle;
String name;
public String getHandle() { return handle; }
public String getName() { return name; }
@JsonIgnore
public String getDisplayName() {
return getName() + “ (" + getHandle() + ")";
}
@Override
public String toString() {
return "User{handle='" + handle + "\', name='" + name + "\', displayName='" + getDisplayName() + "'}";
}
}
_
次に、Firebaseからユーザーを読み取り、それらを新しい場所に書き戻します。
_Firebase srcRef = new Firebase("https://stackoverflow.firebaseio.com/32108969/users");
final Firebase copyRef = new Firebase("https://stackoverflow.firebaseio.com/32108969/copiedusers");
srcRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot usersSnapshot) {
for (DataSnapshot userSnapshot : usersSnapshot.getChildren()) {
User user = userSnapshot.getValue(User.class);
copyRef.child(userSnapshot.getKey()).setValue(user);
}
}
@Override
public void onCancelled(FirebaseError firebaseError) { }
});
_
copiedusers
ノードのJSONは次のようになります。
_"copiedusers": {
"-Jx5vuRqItEF-7kAgVWy": {
"displayName": "Frank van Puffelen (puf)",
"handle": "puf",
"name": "Frank van Puffelen"
},
"-Jx5w3IOHD2kRFFgkMbh": {
"displayName": "Kato Wulf (kato)",
"handle": "kato",
"name": "Kato Wulf"
},
"-Jx5x1VWs08Zc5S-0U4p": {
"displayName": "Jenny Tong (mimming)",
"handle": "mimming",
"name": "Jenny Tong"
}
}
_
Jacksonは新しいgetDisplayName()
メソッドをJavaBeanゲッターとして認識し、出力するJSONにdisplayName
プロパティを追加したため、ソースJSONとは異なります。 JsonIgnore
注釈をgetDisplayName()
に追加することにより、この問題を解決します。
_ @JsonIgnore
public String getDisplayName() {
return getName() + "(" + getHandle() + ")";
}
_
Userオブジェクトをシリアル化するとき、JacksonはgetDisplayName()
メソッドを無視するようになり、書き出すJSONは取得したものと同じになります。
Firebase SDK for Android/Javaの9.x(およびそれ以降)バージョンは、Java <-> JSONのシリアル化/非シリアル化のためのJacksonを含めなくなりました。代わりに、新しいSDKは最小限のカスタムアノテーションセットを提供して、最も一般的なカスタマイズニーズを制御できるようにしますが、結果のJAR/APKサイズへの影響は最小限に抑えます。
私の元の答え は次の場合に有効です:
この回答の残りの部分では、Firebase SDK 9.0以降でのシリアル化/逆シリアル化のシナリオの処理方法について説明します。
FirebaseデータベースのこのJSON構造から始めます。
_{
"-Jx86I5e8JBMZ9tH6W3Q" : {
"handle" : "puf",
"name" : "Frank van Puffelen",
"stackId" : 209103,
"stackOverflowId" : 209103
},
"-Jx86Ke_fk44EMl8hRnP" : {
"handle" : "mimming",
"name" : "Jenny Tong",
"stackId" : 839465
},
"-Jx86N4qeUNzThqlSMer" : {
"handle" : "kato",
"name" : "Kato Wulf",
"stackId" : 394010
}
}
_
最も基本的には、このJSONから各ユーザーを次のJavaクラスにロードできます。
_private static class CompleteUser {
String handle;
String name;
long stackId;
public String getHandle() { return handle; }
public String getName() { return name; }
public long getStackId() { return stackId; }
@Override
public String toString() { return "User{handle='"+handle+"', name='"+name+"', stackId="+stackId+ "'}"; }
}
_
フィールドがパブリックであると宣言する場合、ゲッターさえ必要ありません。
_private static class CompleteUser {
public String handle;
public String name;
public long stackId;
}
_
たとえば、次のようにして、ユーザーを部分的に読み込むこともできます。
_private static class PartialUser {
String handle;
String name;
public String getHandle() {
return handle;
}
public String getName() { return name; }
@Override
public String toString() {
return "User{handle='" + handle + "', NAME='" + name + "''}";
}
}
_
このクラスを使用して同じJSONからユーザーを読み込むと、コードが実行されます(他の回答で言及したJacksonバリアントとは異なります)。ただし、ログ出力には警告が表示されます。
警告:クラスAnnotations $ PartialUserにstackIdのセッター/フィールドが見つかりません
それを取り除くために、クラスに_@IgnoreExtraProperties
_の注釈を付けることができます:
_@IgnoreExtraProperties
private static class PartialUser {
String handle;
String name;
public String getHandle() {
return handle;
}
public String getName() { return name; }
@Override
public String toString() {
return "User{handle='" + handle + "', NAME='" + name + "''}";
}
}
_
前と同様に、計算されたプロパティをユーザーに追加できます。データをデータベースに保存するときに、このようなプロパティを無視する必要があります。これを行うには、プロパティ/ゲッター/セッター/フィールドに_@Exclude
_の注釈を付けることができます。
_private static class OvercompleteUser {
String handle;
String name;
long stackId;
public String getHandle() { return handle; }
public String getName() { return name; }
public long getStackId() { return stackId; }
@Exclude
public String getTag() { return getName() + " ("+getHandle()+")"; }
@Override
public String toString() { return "User{handle='"+handle+"', name='"+name+"', stackId="+stackId+ "'}"; }
}
_
ユーザーをデータベースに書き込むとき、getTag()
の値は無視されます。
また、JavaコードがデータベースのJSONで取得する必要があるから、フィールド/ゲッター/セッターの名前を指定することもできます。これを行うには、フィールド/ゲッター/セッターに@PropertyName()
。
_private static class UserWithRenamedProperty {
String handle;
String name;
@PropertyName("stackId")
long stackOverflowId;
public String getHandle() { return handle; }
public String getName() { return name; }
@PropertyName("stackId")
public long getStackOverflowId() { return stackOverflowId; }
@Override
public String toString() { return "User{handle='"+handle+"', name='"+name+"', stackId="+stackOverflowId+ "'}"; }
}
_
一般に、Firebase SDKが使用するJava <-> JSON間のデフォルトマッピングを使用するのが最善です。ただし、Javaクラスにマップできない既存のJSON構造がある場合は、_@PropertyName
_が必要になる場合があります。
Root.thisのクエリパスフォルダが間違っているため、例
My code:
private void GetUpdates(DataSnapshot snapshot){
romchat.clear();
for (DataSnapshot ds: snapshot.getChildren()){
Rowitemroom row = new Rowitemroom();
row.setCaption(ds.getValue(Rowitemroom.class).getCaption());
row.setFileUrl(ds.getValue(Rowitemroom.class).getFileUrl());
romchat.add(row);
/* Rowitemroom row = snapshot.getValue(Rowitemroom.class);
String caption = row.getCaption();
String url = row.getFileUrl();*/
}
if (romchat.size()>0){
adapter = new CustomRoom(context,romchat);
recyclerView.setAdapter(adapter);
}else {
Toast.makeText(context, "No data", Toast.LENGTH_SHORT).show();
}
}
db_url ="your apps`enter code here`.appspot.com/admins"