Using Android Studio and Firebase, i'm trying to write and read some data.
I have a Pub Class which contains the folowing:
package com.example.jef.pubbuddy.Database;
import java.util.ArrayList;
public class Pub {
private String name;
private float longitude;
private float lattitude;
private ArrayList<Pub> Pubs = new ArrayList<>();
public Pub() {}
public void setName(String name)
{this.name = name;}
public void setLongitude(float longitude)
{this.longitude = longitude;}
public void setLatitude(float lattitude)
{this.lattitude = lattitude;}
public String getName()
{return name;}
public float getLatitude()
{return lattitude;}
public float getLongitude()
{return longitude;}
I write my Pub object to the database using the .push() method. Below is how i write it to the database. It appears just fine in the Firebase console, so I believe the problem doesn't lie here:
Pub p1 = new Pub();
p1.setName("The name of the pub");
p1.setLatitude((float) 4.699545);
p1.setLongitude((float) 50.878267);
myRef.child("PUSH_TEST").push().setValue(p1);
Afterwards I try to read it using the following code. Please note the message method is just used to append some information to a TextView, so i'm able to debug on my physical device. However, none of the listener events get triggered.
Does anyone knows what i'm doing wrong here? Already followed the official firebase documentation and the "Firebase in a weekend" training videos. Also looked up countless answers here on Stackoverflow, but I can't seem to make it work.
Thanks in advance.
public class Database extends AppCompatActivity {
private TextView tv;
int messages;
private ArrayList<Pub> pubList = new ArrayList();
private FirebaseDatabase database;
private DatabaseReference myRef;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_database);
database = FirebaseDatabase.getInstance();
myRef = database.getReference();
init();
writeData();
message("creating and attaching the listener");
ChildEventListener myListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
{
message("The childEvent triggered");
Pub p = dataSnapshot.getValue(Pub.class);
message("The name of this pub = " + p.getName());
pubList.add(p);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
myRef.child("PUSHTEST").addChildEventListener(myListener);
}
Everything is correct, except this:
Here you set the value:
myRef.child("PUSH_TEST").push().setValue(p1);
and here you retrieve the value:
myRef.child("PUSHTEST").addChildEventListener(myListener);
the child that you wrote is wrong as it is not in your database. So just change it into this:
myRef.child("PUSH_TEST").addChildEventListener(myListener);
the name inside child(..) needs to be the same as in your database
You write data to "PUSH_TEST" child and trying to read from "PUSHTEST". Make it same.
For not getting similar errors in future, create a class called "Constants.java" and add constant strings inside it. Like,
public class Constants {
public static final String CHILD_NODE="PUSH_TEST";
}
So that , you can use this constant, where ever u need. Just call Constants.CHILD_NODE. So there will not be such errors.
Related
Getting error:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.ken.careerapp.Models.Jobs
Using a fragment below:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.job_listings_fragment, container, false);
recyclerView = view.findViewById(R.id.recyclerviewjob);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerAdapterJob = new RecyclerAdapterJob(jobs,JobFragment.this::onJobClick);
recyclerView.setAdapter(recyclerAdapterJob);
jobs = new ArrayList<Jobs>();
//initData();
databaseReference = FirebaseDatabase.getInstance().getReference().child("Jobs");
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for(DataSnapshot ds: dataSnapshot.getChildren()){
Jobs data = ds.getValue(Jobs.class);
jobs.add(data);
}
recyclerAdapterJob.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
//recyclerView.setAdapter(new RecyclerViewAdapter2(initData()));
return view;
}
The job model class which is passed to getValue in datasnapshot above:
public class Jobs {
private String description;
private String location;
private String deadline;
public Jobs() {
}
public Jobs(String description, String location, String deadline) {
this.description = description;
this.location = location;
this.deadline = deadline;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDeadline() {
return deadline;
}
public void setDeadline(String deadline) {
this.deadline = deadline;
}
}
FirebaseRealtime database
You are getting the following error:
Getting error: com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.example.ken.careerapp.Models.Jobs
Because you are trying to convert a String, into an object of type Jobs, and this actually not possible in Java. As I see in your screenshot, under the Jobs node, there is only a single Jobs object that contains exactly three String properties. So when you iterate that node, you get String objects back and not Jobs objects, hence that error.
To solve this, you should create multiple objects under that node, as I understand, you want to display them in a RecyclerView. To solve this, you should use the push() method, when you add those jobs to the database. You didn't share that part of code, but I imagine that looks similar to this:
databaseReference = FirebaseDatabase.getInstance().getReference().child("Jobs");
databaseReference.setValue(jobs);
In which jobs is an object of type Jobs. This is not correct, as it produces that error when reading data. To solve this, please change the above line of code to:
databaseReference.push().setValue(jobs);
In this case, your new structure will look like this:
Firebase-root
|
--- Jobs
|
--- pushedId
|
---deadline: "September"
|
---description: "Intern Software Developer"
|
---location: "Moi Avenue Street"
And the rest of the code should work.
P.S.
Don't ignore potential errors!
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage());
}
Always log the error message.
Give a photo or your realtime database architecture.
that will help much to ans this issue.
I am trying to writing data in an activity and then reading it in another activity. My writing part is working. For my reading part, I am trying to use getValue with parameter of a class I wrote. But I keep getting this error:
com.google.firebase.database.DatabaseException: Class ozhan.climb.MainActivity$User does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped.
My class that used in getValue():
class User {
public String Server,
NeededRole,
Role,
SummonerName;
User() {}
public String get_Server() {
return Server;
}
public String get_NeededRole() {
return NeededRole;
}
public String get_Role() {
return Role;
}
public String get_SummonerName() {
return SummonerName;
}
}
and here is the code that should get data:
public void getUserData(){
final TextView tv_sumName = findViewById(R.id.tv_sumName),
tv_neededRole = findViewById(R.id.tv_neededrole),
tv_userRole = findViewById(R.id.tv_userrole),
tv_server = findViewById(R.id.tv_server);
final String uid = Objects.requireNonNull(mAuth.getCurrentUser()).getUid();
DatabaseReference usersDataRef = databaseRef.child("Users").child(uid);
usersDataRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null) {
tv_server.setText(u.Server);
tv_neededRole.setText(u.NeededRole);
tv_userRole.setText(u.Role);
tv_sumName.setText(u.SummonerName);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The exception says your class is ozhan.climb.MainActivity$User - i.e., it is an inner class of MainActivity.
Inner classes require an instance of their outer class to construct. This won't work with Firebase Database, although the error message could definitely be improved.
Your User class should be a static class, which does not have the same requirement to exist only within the instance of a containing class:
static class User {
...
}
So I'm working on an app that uses an authorization system to log users in. Whenever a user registers, it updates just fine in my database:
User user = new User(username);
FirebaseDatabase.getInstance().getReference().child("users").child(userid).child("profile").setValue(user);
The problem is, that when I try to access the data again in my next activity to try and get the current user's username, I get this error message:
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type friendimals.Model.User
I'm using a basic model class:
public class User {
private String username;
public User() {
}
public User(String username) {
this.username= username;
}
public String getUsername(){
return this.username;
}
}
This is how I'm accessing the information in my database:
mDatabase.child("users").child(mUserId).child("profile").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//This is the line that is causing the crash
User user = dataSnapshot.getValue(User.class);
username_TextView.setText(user.getUsername());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Any ideas on what this error means and/or how to fix it? Any help is greatly appreciated.
The problem is you don't have any key called username which you are specified in the model class. dataSnapshot only return the String value.
if your data structure is like this then only that work with model class
userid
|
username:usernameValue
I am using Firebase.
1. Question:
I create a Key with:
final String CHATS_CHILD = "chats/" + mFirebaseDatabaseReference.push().getKey();
mFirebaseDatabaseReference.child(CHATS_CHILD).push().setValue("and so on...");
The result you see in the picture. Now I created a key with childrens in Firebase but how to I get the key into my android app? (I mean the first key, after Chats)
2. Qestion is similar
You see the databe in my Picture. How can I get the first key after chats, when I search after the text? So for example I want the key which has as child the Text "Test1"
How to do that?
Thanks in advance.
I think you should flatten your data in order to get message key and chat key using just message text. You can keep actual messages in a separate path (like "messages") and keep only message keys inside related chat's path, as shown in the following structure:
Create Chat class:
public class Chat {
private Map<String, Boolean> messageKeys;
public Chat() {
// Default constructor required for calls to DataSnapshot.getValue(Chat.class)
}
public Chat(Map<String, Boolean> messageKeys) {
this.messageKeys = messageKeys;
}
public Map<String, Boolean> getMessageKeys() {
return messageKeys;
}
public void setMessageKeys(Map<String, Boolean> messageKeys) {
this.messageKeys = messageKeys;
}
}
..and Message class:
public class Message {
private String chatKey;
private String text;
private long time;
public Message() {
// Default constructor required for calls to DataSnapshot.getValue(Message.class)
}
public Message(String chatKey, String text, long time) {
this.chatKey = chatKey;
this.text = text;
this.time = time;
}
public String getChatKey() {
return chatKey;
}
public void setChatKey(String chatKey) {
this.chatKey = chatKey;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}
Then query messages and find those whose text field is equal to the term you are searching, for example "Test1":
DatabaseReference chatsRef = FirebaseDatabase.getInstance().getReference("chats");
DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");
messagesRef.orderByChild("text").equalTo("Test1").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
String messageKey = child.getKey();
Message message = child.getValue(Message.class);
String chatKey = message.getChatKey();
// Now you have both the chatKey and the messageKey...
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
Creating a new chat and its first message would look like below in this case (can be considered as answer to your first question):
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
String chatKey = rootRef.push().getKey();
String messageKey = rootRef.push().getKey();
Message newMessage = new Message(chatKey, "My message trial", Calendar.getInstance().getTimeInMillis());
Map<String, Boolean> messageKeys = new LinkedHashMap<>();
messageKeys.put(messageKey, true);
Chat newChat = new Chat(messageKeys);
rootRef.child("messages").child(messageKey).setValue(newMessage);
rootRef.child("chats").child(chatKey).setValue(newChat);
Retrieving all messages that belongs to a chat whose key is known:
String chatKey = "chatKey1"; // Get it somehow
DatabaseReference messagesRef = FirebaseDatabase.getInstance().getReference("messages");
messagesRef.orderByChild("chatKey").equalTo(chatKey).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Message> messageList = new ArrayList<>();
for (DataSnapshot child : dataSnapshot.getChildren()) {
String messageKey = child.getKey();
Message message = child.getValue(Message.class);
messageList.add(message);
}
// Now you have all messages in messageList...
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
in additional to answer of Mehmed: Firebase DB supports not only setting/retrieving single fields, but also whole the objects of some class.
In the example below I define class MyChat, create few objects of it and put them into Firebase DB. Then I retrieve all of them (as objects, not just strings) and put them into ArrayList.
FirebaseDatabase frDb = FirebaseDatabase.getInstance();
DatabaseReference mFirebaseDatabaseReference = frDb.getReference();
final String CHATS_CHILD = "chats/theChat" ; //+ mFirebaseDatabaseReference.push().getKey();
// Create 3 objects of class MyChat
MyChat chat1 = new MyChat("Test1", "21-Sep-2017");
MyChat chat2 = new MyChat("Test21", "26-Sep-2017");
MyChat chat3 = new MyChat("TestB", "28-Sep-2010");
//Add all the chats to Firebase DB
mFirebaseDatabaseReference.child(CHATS_CHILD).push().setValue(chat1);
mFirebaseDatabaseReference.child(CHATS_CHILD).push().setValue(chat2);
mFirebaseDatabaseReference.child(CHATS_CHILD).push().setValue(chat3);
// Here we will retrieve all the chats and put them to array
// Declare array to keep results
final ArrayList<MyChat> arr1 = new ArrayList<MyChat>();
//Listener
ChildEventListener chEvLst = mFirebaseDatabaseReference.child("chats").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
for (DataSnapshot ds1 : dataSnapshot.getChildren()) {
MyChat chatRes = ds1.getValue(MyChat.class);
Log.i("Next chat text:",chatRes.getmText());
Log.i("Next chat date:",chatRes.getmText());
arr1.add(chatRes); // retrieve and save chats to array
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
And this is class MyChat
public class MyChat {
String mText = "Test1"; // default values...
String mDate = "26-Sep-2017";
// *** MUST TO HAVE EMPTY CONSTUCTOR FOR FIREBASE !!! ***
public MyChat() {
}
// Second constructor
public MyChat(String mText, String mDate) {
this.mText = mText;
this.mDate = mDate;
}
// *** MUST TO HAVE ALL GETTERS/SETTERS FOR FIREBASE!!! ***
// Getters/setters
public String getmText() {
return mText;
}
public void setmText(String mText) {
this.mText = mText;
}
public String getmDate() {
return mDate;
}
public void setmDate(String mDate) {
this.mDate = mDate;
}
}
And this is resulting DB structure :
Best regards!
How Can I get ArrayList of Java Objects of all Childs from Firebase using updated firebase commands, currently I am using below approach but not able to get the list.
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
if(dataSnapshot!=null){
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
UserDataClass post = postSnapshot.getValue(UserDataClass.class);
members.add(post);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
}
};
mDatabaseRef.addValueEventListener(postListener);
below is datasnapshot which is returning from firebase but I am not able to get the desired result out of it.
DataSnapshot { key = 12345, value = {Members={00000000={phoneNo=00000000, longitude=73.0703307, latitude=33.6396975, password=qwertyuiop, CName=00000000, admin=true, name=Anwar Kamal}, 03028084374={phoneNo=03028084374, longitude=73.0701292, latitude=33.6397129, password=qwerty, CName=00000000, admin=false, name=Nehal Khan}, 03028084516={phoneNo=03028084516, longitude=73.0702659, latitude=33.6397622, password=qwerty, CName=03035356317, admin=false, name=Jamal Khan}}} }
all i want is list of all members
and my java object is
public class UserDataClass {
public double latitude;
public double longitude;
public String Name="";
public String password="";
public String phoneNo="";
public String CircleName="";
public boolean isAdmin=false;
}
The ValueEventListener has another purpose.
You should use ChildEventListener and also dataSnapshop.getValue() to implement what you want, for example:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
UserDataClass post = postSnapshot.getValue(UserDataClass.class);
members.add(post);
}
//...
Note:
You should use the listener with the current firebase_referance to the Users table. Hence you should replace
mDatabaseRef.addValueEventListener(postListener);
with
mDatabaseRef.child("Members").addChildEventListener(childEventListener);
notice that your full path of the Members table is colored and i couldn't figure the path.
You can find the whole documentation here
good luck