Problems getting data on Android with Firebase
I just learned how to set up Firebase data on Android. I can write a db, but I cannot read and display it in my application. My application is very simple (it only has one main screen at the moment) and I don't care how the data is displayed on the page as I'm just learning - I'm currently trying to display it as text.
Here is my main java activity:
package com.example.ispotrachel.myapplication;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.firebase.client.DataSnapshot;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.firebase.client.ValueEventListener;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
Firebase ref = new Firebase("https://blistering-torch-9015.firebaseio.com");
class User {
private int birthYear;
private String fullName;
public User() {
}
public User(String fullName, int birthYear) {
this.fullName = fullName;
this.birthYear = birthYear;
}
public long getBirthYear() {
return birthYear;
}
public String getFullName() {
return fullName;
}
}
User user1 = new User("Name 1", 1982);
User user2 = new User("Name 2", 1972);
Firebase usersRef = ref.child("users");
Map<String, User> users = new HashMap<String, User>();
users.put("user1", user1);
users.put("user 2", user2);
usersRef.setValue(users);
Firebase postRef = ref.child("posts");
Map<String, String> post1 = new HashMap<String, String>();
post1.put("author", "user1");
post1.put("title", "Announcing COBOL, a New Programming Language");
postRef.push().setValue(post1);
Map<String, String> post2 = new HashMap<String, String>();
post2.put("author", "user2");
post2.put("title", "The Turing Machine");
postRef.push().setValue(post2);
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot arg0) {
//System.out.println(arg0.getValue());
TextView textViewSample = (TextView) findViewById(R.id.sampleTextView);
textViewSample.setText(arg0.getValue(String.class));
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("the read failed");
}
});
}}
Here is my activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/sampleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world"/>
</LinearLayout>
When I run the application, it crashes. Here is the logcat error message:
12-27 12:15:02.678 1895-1895/com.example.ispotrachel.myapplication I/art﹕ Not late enabling -Xcheck:jni (already on)
12-27 12:15:02.946 1895-1907/com.example.ispotrachel.myapplication I/art﹕ Background sticky concurrent mark sweep GC freed 3867(286KB) AllocSpace objects, 0(0B) LOS objects, 11% free, 1009KB/1135KB, paused 2.595ms total 117.910ms
12-27 12:15:03.317 1895-1926/com.example.ispotrachel.myapplication D/OpenGLRenderer﹕ Render dirty regions requested: true
12-27 12:15:03.320 1895-1895/com.example.ispotrachel.myapplication D/﹕ HostConnection::get() New Host Connection established 0xa6667e80, tid 1895
12-27 12:15:03.327 1895-1895/com.example.ispotrachel.myapplication D/Atlas﹕ Validating map...
12-27 12:15:03.391 1895-1926/com.example.ispotrachel.myapplication D/﹕ HostConnection::get() New Host Connection established 0xa66ef3b0, tid 1926
12-27 12:15:03.405 1895-1926/com.example.ispotrachel.myapplication I/OpenGLRenderer﹕ Initialized EGL, version 1.4
12-27 12:15:03.422 1895-1926/com.example.ispotrachel.myapplication D/OpenGLRenderer﹕ Enabling debug mode 0
12-27 12:15:03.439 1895-1926/com.example.ispotrachel.myapplication W/EGL_emulation﹕ eglSurfaceAttrib not implemented
12-27 12:15:03.439 1895-1926/com.example.ispotrachel.myapplication W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa66b7880, error=EGL_SUCCESS
12-27 12:15:07.474 1895-1926/com.example.ispotrachel.myapplication W/EGL_emulation﹕ eglSurfaceAttrib not implemented
12-27 12:15:07.474 1895-1926/com.example.ispotrachel.myapplication W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa66b7880, error=EGL_SUCCESS
12-27 12:15:13.993 1895-1895/com.example.ispotrachel.myapplication D/AndroidRuntime﹕ Shutting down VM
--------- beginning of crash
12-27 12:15:13.993 1895-1895/com.example.ispotrachel.myapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.ispotrachel.myapplication, PID: 1895 com.firebase.client.FirebaseException: Failed to bounce to type
at com.firebase.client.DataSnapshot.getValue(DataSnapshot.java:196)
at com.example.ispotrachel.myapplication.MainActivity$1.onDataChange(MainActivity.java:79)
at com.firebase.client.core.ValueEventRegistration$1.run(ValueEventRegistration.java:48)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: java.io.StringReader@c8f7297; line: 1, column: 1]
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:575)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:46)
at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
at com.firebase.client.DataSnapshot.getValue(DataSnapshot.java:192)
at com.example.ispotrachel.myapplication.MainActivity$1.onDataChange(MainActivity.java:79)
at com.firebase.client.core.ValueEventRegistration$1.run(ValueEventRegistration.java:48)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)device not found
source to share
TL; DR
It looks like you are trying to load a JSON object into a string.
The error message Failed to bounce to type
indicates that the Firebase client has returned some data, but cannot convert it to the type you specified.
Problem Details
You add ValueEventListener
to the root of your Firebase here:
ref.addValueEventListener(new ValueEventListener() { ...
In this value event listener, you are telling Firebase to load the whole Firebase as String
:
textViewSample.setText(arg0.getValue(String.class));
And it would work if you had a very simple Firebase containing only one line. However, based on the rest of your code, it looks like your Firebase has a lot more String
in it :)
How to fix it You have several options:
-
Attach an event listener further down the tree. You can get the user's full name as a string:
ref.child("users/user1/fullName").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot arg0) { TextView textViewSample = (TextView) findViewById(R.id.sampleTextView); textViewSample.setText(arg0.getValue(String.class)); } ... }
-
Or you can get the whole user, but parse it like
User
insteadString
:ref.child("users/user1/fullName").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot arg0) { User tempUser = arg0.getValue(User.class); TextView textViewSample = (TextView) findViewById(R.id.sampleTextView); textViewSample.setText(tempUser.getFullName()); } ... }
source to share
I have a similar problem.
This is the code from which I am fetching data from firebase:
DatabaseReference chatRef = database.getReference("chats");
chatRef.keepSynced(true);
Query queryRef = chatRef.orderByChild("id");
queryRef.addChildEventListener(new ChildEventListener() {
// Retrieve new posts as they are added to the database
@Override
public void onChildAdded(DataSnapshot snapshot, String previousChildKey) {
ChatPost newPost = snapshot.getValue(ChatPost.class);
ChatPost topic = new ChatPost(newPost.id, newPost.topic);
addChatTopic(topic);
System.out.println("NEW Child Topic: " + newPost.topic);
chatAdapter.addItem(newPost);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
ChatPost newPost = dataSnapshot.getValue(ChatPost.class);
ChatPost topic = new ChatPost(newPost.id, newPost.topic);
addChatTopic(topic);
System.out.println("CHANGED Child Topic: " + newPost.topic);
chatAdapter.updateItem(newPost);
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
ChatPost newPost = dataSnapshot.getValue(ChatPost.class);
ChatPost topic = new ChatPost(newPost.id, newPost.topic);
chatTopicsList.add(topic);
System.out.println("REMOVED Child Topic: " + newPost.topic);
chatAdapter.removeItem(newPost);
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
It worked until I used push () to add a new item. My data in firebase console looks like here .
Exception text:
07-05 16: 45: 07.097 29997-29997 / com.skl.bingofire E / AndroidRuntime: FATAL EXCEPTION: Main Process: com.skl.bingofire, PID: 29997 com.google.firebase.database.DatabaseException: List expected during deserialization, but got the java.util.HashMap class at com.google.android.gms.internal.zzaix.zza (Unknown source) at com.google.android.gms.internal.zzaix.zza (Unknown source) at com.google .android.gms.internal.zzaix.zzb (Unknown source) at com.google.android.gms.internal.zzaix $ zza.zze (Unknown source) at com.google.android.gms.internal.zzaix $ zza.zzaC (Unknown source) at com.google. android.gms.internal.zzaix.zzd (Unknown source) at com.google.android.gms.internal.zzaix.zzb (Unknown source) at com.google.android.gms.internal.zzaix.zza (Unknown source) at com.google.firebase.database.DataSnapshot.getValue (Unknown source) at com.skl.bingofire.activities.MainActivity $ 7.onChildAdded (MainActivity.java:228) at com.google.android.gms.internal.zzaer.zza (Unknown source) at com.google.android. gms.internal.zzagp.zzSu (Unknown source) at com.google.android.gms.internal.zzags $ 1.run (Unknown source) on android.os.Handler.handleCallback (Handler.java:739) on android.os. Handler.dispatchMessage (Handler.java:95) at android.os.Looper.loop (Looper.java:148) at android.app.ActivityThread.main (ActivityThread.java:5417) at java.lang.reflect.Method.invoke (native method) at com.android .internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:616) 07-05 16: 45: 16.924 29997-30029 / com. skl.bingofire E / DynamiteModule: Failed load module descriptor class: Could not find class' Com.google.android.gms.dynamite.descriptors.com.google.firebase.auth.ModuleDescriptor "along the path: DexPathList [[zip file" /data/app/com.skl.bingofire-1/base.apk "], nativeLibraryDirectories = [/ data / app / com.skl.bingofire-1 / lib / arm, / vendor / lib, / system / lib]]
I used this model:
class ChatPost {
public String id;
public String topic;
public String color;
public ArrayList<Message> messages;
}
I figured out that if the data list contains a key like "-KLdskjdkjkjdjksjdksjdjsdjsjk", firebase will recognize the hole list as "HashMap" otherwise as "ArrayList". I changed my model to this structure:
class ChatPost {
public String id;
public String topic;
public String color;
public HashMap<String, Message> messages;
}
And I added a chat with a key like "-KLdskjdkjkjdjksjdksjdjsdjsjk" to the rest of the messages. And my code is working now. But I think this is not obvious.
source to share