I'm trying to retrieve data from Firebase database to add it to local database.
This code :
database = FirebaseDatabase.getInstance();
myRef = database.getReference();
Query LANGUAGES_REF = myRef.child("languages").orderByChild("id");
LANGUAGES_REF.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
if (dataSnapshot.hasChildren()) {
Iterator<DataSnapshot> iterator = dataSnapshot.getChildren().iterator();
do {
Language language = iterator.next().getValue(Language.class);
languageR.insert(language);
} while (iterator.hasNext());
}
is not working , and I know it's because Language.class is an entity.
Is there a way other than creating a new class with getters and setters and full constructor ... and repeating everything??
The error I got was:
com.google.firebase.database.DatabaseException: Can't convert object
of type java.lang.Long to type
com.android.android.Database.Entities.Language
at this line :
Language language = iterator.next().getValue(Language.class);
Thanks
edit:
firebase database structure
"languages" : {
"LHZ7cAeOdPn-LwHNjIk" : {
"id" : 1,
"langName" : "Russian"
},
"LHZ7cAtXTGBlnWsdQOd" : {
"id" : 2,
"langName" : "French"
},
"LHZ7cAvrRs0rgI-PaJd" : {
"id" : 3,
"langName" : "Turkish"
}
}
language.class
import java.io.Serializable;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
#Entity
public class Language implements Serializable {
#PrimaryKey(autoGenerate = true)
private int id;
private String langName;
public int getId() {
return id;
}
public String getLangName() {
return langName;
}
public Language(String langName) {
this.langName = langName;
}
public void setId(int id) {
this.id = id;
}
}
To solve this, you need to remove the do-while loop because there is no need to iterate using getChildren() method, you can get the data directly from the dataSnapshot object like this:
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Language language = dataSnapshot.getValue(Language.class);
languageR.insert(language);
Log.d(TAG, language.getLangName());
}
The output in your logcat will be:
Russian
French
Turkish
Related
Recently I use Firebase in my Android application and try to get used of NoSQL data structure but I met some problems.
First, my data structure is very simple:
{
"user": {
"userid1" :{
"id: "userid1"
"name": "Samantha",
"age": 25
"email" : "abc#gmail.com"
}
}
}
So I wrote my Entity class like this
public class User implements Serializable {
private String id;
private String name;
private int age;
private String email;
}
When I want to get all user into list:
FirebaseDatabase.getInstance().getReference("user").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot dataSnapshot : snapshot.getChildren()){
User user = dataSnapshot.getValue(User.class);
listUser.add(user);
}
}
}
But if I want to change my data structure like this, I don't know how to do the same:
{
user: {
userid1 :{
id: "userid1"
name: "Samantha",
age: 25
email : "abc#gmail.com"
posts:{
postid1: {
postid : "postid1"
content : "content1"
}
postid2: {
postid : "postid2"
content : "content2"
}
}
}
}
}
I figure I have to create a Post entity class but how can I fetch list of user like before? Anyone can explain to me would be helpful.
Nesting data like you want to do is an anti-pattern in Firebase, and goes against the recommendations in the documentation on data structuring. See https://firebase.google.com/docs/database/android/structure-data#best_practices_for_data_structure
That said: if you have a structure like this, you can read it by adding posts map to the class to read its data:
public class User implements Serializable {
public String id;
public String name;
public int age;
public String email;
public Map<String, Object> posts;
}
If you want to get them type-safely, you might need to use a GenericTypeIndicator.
I'm not getting the output from Firebase database. It's not returning anything. Here is my data structure.
I also tried getting value through query but it returned database error:
Cannot convert java.util.hashmap to String
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference().child("Member").push();
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String value = ds.getValue(String.class);
Log.d("Tag", "Value is" + value);
}
}
JSON:
{
"Member" : {
"-LhKJVG1Tj2628sHPg4D" : {
"age" : "21",
"name" : "Gagan",
"nickname" : "Gaggi"`enter code here`
},
"-LhKKaNFnPrrh1bQNPfH" : {
"age" : "18",
"name" : "Jashan",
"nickname" : "Jassi"
}
}
}
You cannot call getValue with String.class because it does not meet the criteria of the method call.
From the documentation
public T getValue(Class valueType)
This method is used to marshall the data contained in this snapshot into a class of your choosing. The class must fit 2 simple constraints:
The class must have a default constructor that takes no arguments
The class must define public getters for the properties to be assigned. Properties without a public getter will be set to their default value when an instance is deserialized
An example class might look like:
class Message {
private String author;
private String text;
private Message() {}
public Message(String author, String text) {
this.author = author;
this.text = text;
}
public String getAuthor() {
return author;
}
public String getText() {
return text;
}
}
// Later
Message m = snapshot.getValue(Message.class);
You can use String class
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name= ds.child("name").getValue(String.class);
String age= ds.child("age").getValue(String.class);
//and similar for others
Log.d("TAG", email + " / " + name);
}
}
So this is my bind model class:
public class UserBanknoteAmountBindModel {
public String id;
public String userId;
public String banknoteType;
public String banknoteAmount;
public UserBanknoteAmountBindModel(){
}
public String getBanknoteAmount() {
return banknoteAmount;
}
public String getBanknoteType() {
return banknoteType;
}
public String getUserId() {
return userId;
}
public void setBanknoteAmount(String banknoteAmount) {
this.banknoteAmount = banknoteAmount;
}
public void setBanknoteType(String banknoteType) {
this.banknoteType = banknoteType;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
(idk if acess modifiers matter in this case).
I am trying to parse my data:
for (DataSnapshot banknoteAmount:dataSnapshot.getChildren()){
UserBanknoteAmountBindModel userBanknoteAmountBindModel=dataSnapshot.getValue(UserBanknoteAmountBindModel.class);
Log.wtf("hgfh", banknoteAmount.getValue().toString());
}
I see that I am receiving my data because I can log it.
{banknoteAmount=3, banknoteType=20_dollar,
userId=112371098270685247195}
Anyway my data doesn't get inside my bind model. I read somewhere that I need not only to provide getters but also setters (that's why I put those setters PS: Is the thing for the setters true?).
Any ideas?
EDIT: Database Structure https://i.stack.imgur.com/o5Hgp.png
PS: The problem was that I was using the parameter from another function for the getValue (not the foorloop variable)
To get the values of banknoteAmount, banknoteType and userId, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userBanknoteAmountRef = rootRef.child("userBanknoteAmount");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
UserBanknoteAmountBindModel userBanknoteAmountBindModel = ds.getValue(UserBanknoteAmountBindModel.class);
String banknoteAmount = userBanknoteAmountBindModel.getBanknoteAmount();
String banknoteType = userBanknoteAmountBindModel.getBanknoteType();
String userId = userBanknoteAmountBindModel.getUserId();
Log.d("TAG", banknoteAmount + " / " + banknoteType + " / " + userId);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
userBanknoteAmountRef.addListenerForSingleValueEvent(valueEventListener);
The output will be:
3 / 20_dollar / 112371098270685247195
When you are using the following line of code:
banknoteAmount.getValue().toString()
You are actually printing the String representation of banknoteAmount.getValue() which has as a return value a Map object which contains those three values.
I have a custom list adapter that has many methods that query the database and add data to different java objects or lists.
code to consider in adapter as follows: -
static class ViewHolder {
ArrayList<String> imgUrls;
//other variables;
}
then initiated it in getView method as:-
public View getView(#params) {
holder.imgUrls = new ArrayList<>();
}
//i have a method that query and retrieve data from firebase as follows:-
public void getPhoto(final ViewHolder holder) {
Query query = reference
.child(mContext.getString(R.string.dbname_collections))
.child(holder.collection.getCollection_id())
.child("photo_url");
query.keepSynced(true);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) {
imgUrl = singleSnapshot.getValue(String.class);
Log.d(TAG, "onDataChange: imgUrl: " + imgUrl);
holder.imgUrls.add(imgUrl);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.d(TAG, "getPhoto: list with values " + holder.imgUrls);
}
My database in firebase console look like this:-
{
"collections": {
"-L9nNSyF7ZhEqpvmPo0Z": {
"caption": "jakhaha",
"collection_id": "-L9nNSyF7ZhEqpvmPo0Z",
"date_created": "2018-04-11T11:55:57Z",
"photo_url": [
"https://firebasestorage.googleapis.com/v0/b/backbench-72a47.appspot.com/o/collection%2Fusers%2FHb8ORoozQ3WhyxjaSyqazjHypkf2%2F2018-04-11T11%3A55%3A57Z%2Fphoto0?alt=media&token=08fdb740-9b16-455b-83ec-bfcec1455834",
"https://firebasestorage.googleapis.com/v0/b/backbench-72a47.appspot.com/o/collection%2Fusers%2FHb8ORoozQ3WhyxjaSyqazjHypkf2%2F2018-04-11T11%3A55%3A57Z%2Fphoto1?alt=media&token=eeca4b10-0729-4ca9-be18-c31d054add19",
"https://firebasestorage.googleapis.com/v0/b/backbench-72a47.appspot.com/o/collection%2Fusers%2FHb8ORoozQ3WhyxjaSyqazjHypkf2%2F2018-04-11T11%3A55%3A57Z%2Fphoto2?alt=media&token=b33c97b0-c2bf-4199-bef0-b498f505a678"
],
//this are the imageUrls i want to retrieve as a arrylist
"tags": "#NoTags",
"user_id": "Hb8ORoozQ3WhyxjaSyqazjHypkf2"
}
}
}
in my firebase model class :-
public class Collection implements Parcelable {
//properties for photo (*case sensitive*)
private String caption;
private String date_created;
private String collection_id;
private String user_id;
private String tags;
//list of likes
private List<String> photo_url;
private List<Like> likes;
private List<Comment> comments;
public Collection() {
}
//constructor..getter setters etc...
}
in my log console i see that values of imgUrl are fatched
04-11 20:35:03.992 21269-21269/com.backbenchers.administrator.instaclone D/CollectionListAdapter: onDataChange: imgUrl://url of image 1
onDataChange: imgUrl: url of image 2
onDataChange: imgUrl: ...image 3
but it shows list as null or [] :-
D/CollectionListAdapter: getPhoto: list is with values : []
"I want to fetch this firebase data and add it to an arraylist.."
what is wrong ??
Thanks!
I'm unable to retrieve the data which is nested inside "Leagues" and "Season".
In the database below, I cannot retrieve Season 2016/2017 points and results.
I am able to access the data that is not nested, such as Email and Username without problems
"Users" :
"User1" : {
"Email" : "dfs#sdf.com",
"Last_login" : "5:15pm",
"Username" : "Test",
"Leagues" : {
"FootballLeague" : true,
"CricketLeague" : true
},
"Season" : {
"2017" : {
"Points" : 5,
"Results" : 2
"newdata" : {
"randomdata1: data1",
"randomdata2: data2"
},
}
"2018" : {
"Points" : 7,
"Results" : 2
}
}
The following class is what I'm using to store data as objects:
public class Users {
private String Username;
private String Email;
private String Last_login;
private Map<String, Boolean> Leagues;
private Map<String, thisSeason> Season;
public Users() {
}
//All getters and setters for the strings.
public Map<String, Boolean> get_joined_Leagues() {
return Leagues;
}
public void set_joined_Leagues(Map<String, Boolean> leagues) {
Leagues = leagues;
}
public Map<String, thisSeason> getSeason() {
return Season;
}
public void set_thisSeason(Map<String, thisSeason> season) {
Season = season;
}
public static class thisSeason {
private int Points;
private int Results;
private Map <String, thisNewData> newdata;
public thisSeason() {
}
public int getthisSeason_results() {
return Results;
}
public void setthisSeason_results(int resultsin) {
Results = resultsin;
}
public int getthisSeason_points() {
return Points;
}
public void setSeason_points(int Pointsin) {
Points = Pointsin;
}
public Map<String, thisNewData> getNewData() {
return newdata;
}
public void set_thisNewData(Map<String, thisNewData> newdata_in) {
newdata= newdata_in;
}
public static class thisNewData {
private String randomdata1;
private String randomdata2;
//Getters and Setters
}
Here is part of my Java class where I access the Database:
List<Users> usersList= new ArrayList<Users>();
DatabaseReference fbDB = FirebaseDatabase.getInstance().getReference();
fbDB.child("Users").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Users C = ds.getValue(Users.class);
usersList.add(C);
System.out.println(C.getSeason().getthisSeason_points()); //ERROR occurs here - null object reference
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I get a null object reference error as shown in the code above.
Also, on a slight side note - I'm aware my implementation for getting Leagues is incorrect. How can I retrieve the keys instead?
The main problems that I found in your code:
First, your Leagues object:
Well, it should not be a custom object at all, if it stays in the current structure, but a Map. This is the map object - a collection which has a key, and a value, just like a child in the Realtime Database.
If a league name (=key) didn't have a true (=value) next to it - the names could have been stored in String variables, but this is not the case, because every child in the Realtime Database must have a value, and storing a "dummy" value next to a league name makes each league a part of a Map. This current "dummy" is a boolean, and that's why this will be the leagues' data type:Map<String, Boolean> leagues.
Second, your Season object:
You are confusing between one season and many seasons. Your child - "Season" actually stores a lot of seasons. Thats why this case will be similar to the one above - each season's time is the key and the season itself is the value.
Therefore, the User class's variables should be:
private String Username;
private String Email;
private String Last_login;
private Map<String,Boolean> Leagues;
private Map<String, Season> Seasons;