I have a Firebase databse structure like this :
the firebase database structure
Now I want to access the items in the node "comingSoonPages" to a model class. How can i get the reference to these different user specified items in that node?
The database reference :
mUpcomingDatabaseReference = mFirebaseDatabase.getReference().child("comingSoonPages").child("blrKoramangala")
now the listener to the reference is as :
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapShot : dataSnapshot.getChildren()){
Log.e("snap" , String.valueOf(snapShot));
try{
UpcomingProperty property = snapShot.getValue(UpcomingProperty.class);
Log.e("name" , String.valueOf(property.getName()));
}catch (Exception ex){
ex.printStackTrace();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
mUpcomingDatabaseReference.addValueEventListener(mValueEventListener);
when i try to log the names in each of the nodes , i get NPE and the value is null.
The model class in which i am mapping is :
public class UpcomingProperty implements Serializable {
//private Amenities amenities;
private List<String> amenities;
private Coordinates coordinates;
private Image image;
private String link;
private String location;
private String name;
private Text text;
private List<String> sortParameter;
private EarlyBird earlyBird;
public UpcomingProperty(){}
public List<String> getAmenities() {
return amenities;
}
public void setAmenities(List<String> amenities) {
this.amenities = amenities;
}
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Text getText() {
return text;
}
public void setText(Text text) {
this.text = text;
}
public List<String> getSortParameter() {
return sortParameter;
}
public void setSortParameter(List<String> sortParameter) {
this.sortParameter = sortParameter;
}
public EarlyBird getEarlyBird() {
return earlyBird;
}
public void setEarlyBird(EarlyBird earlyBird) {
this.earlyBird = earlyBird;
}
}
Thanks.
the extended firebase node :
extended node values
To get that data, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference comingSoonPagesRef = rootRef.child("comingSoonPages");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.child("name").getValue(String.class);
Log.d("TAG", name);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
comingSoonPagesRef.addListenerForSingleValueEvent(eventListener);
The out will be the only the names. But you can get also all the other values in the same way.
If you want to use the model class, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference comingSoonPagesRef = rootRef.child("comingSoonPages");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
UpcomingProperty upcomingProperty = ds.getValue(UpcomingProperty.class);
Log.d("TAG", upcomingProperty.getName());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
comingSoonPagesRef.addListenerForSingleValueEvent(eventListener);
You'll have the same output.
Assuming that comingSoonPages holds a list of item, You need to add a ChildEventListener on the comingSoonPages reference if you want to access all the child nodes of that.
DatabaseReference upcomingItemsRef = mFirebaseDatabase.getReference().child("comingSoonPages");
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
if(dataSnapshot.exists()) {
// Handle each individual node like blrKoramangala, cyberHub here.
String key = dataSnapshot.getKey();
// Get the UpcomingProperty object here.
UpcomingProperty property = dataSnapshot.getValue(UpcomingProperty.class);
Log.d(TAG, "property.getName():" + property.getName();
}
}
// Other methods of ChildEventListener go here
};
upcomingItemsRef.addChildEventListener(childEventListener);
You can read more about working with lists of data here.
However, if that's not a list, here's what you're doing wrong:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Don't do this. It will get the children of blrKoramangala and
// those won't be of UpcomingProperty type.
// Remove and replace with dataSnapshot.exists()
for (DataSnapshot snapShot : dataSnapshot.getChildren()){
...
}
}
Related
I'm loading data From firebase and I want to display it in recyclerview using MVVM
I retrieved data from firebase and it works fine.
But I want to use adapter.notifyDataSetChanged(); to update recyclerview in Repo class
this is my repo class:
public class CategoriesRepo {
private static CategoriesRepo instance;
private final ArrayList<Cat> categoriesModel = new ArrayList<>();
private DatabaseReference dbCategories;
public static CategoriesRepo getInstance() {
if (instance == null) {
instance = new CategoriesRepo();
}
return instance;
}
public MutableLiveData<ArrayList<Cat>> getCategories() {
loadCats();
MutableLiveData<ArrayList<Cat>> categories = new MutableLiveData<>();
categories.setValue(categoriesModel);
return categories;
}
private void loadCats() {
dbCategories = FirebaseDatabase.getInstance().getReference("categories");
dbCategories.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NotNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.getKey();
// this is not showing in recyclerview
categoriesModel.add(new Cat("Name", 1));
Log.d("TAGD", "onDataChange: " + ds.getKey() + " " + categoriesModel.size());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
Is there any way to update recyclerview using MVVM?
LiveData will provide callback on value change i.e setValue or postValue . So you need to set the value after you get the data not before .
public class CategoriesRepo {
private static CategoriesRepo instance;
private DatabaseReference dbCategories;
private MutableLiveData<ArrayList<Cat>> categories = new MutableLiveData<>();
public static CategoriesRepo getInstance() {
if (instance == null) {
instance = new CategoriesRepo();
}
return instance;
}
public MutableLiveData<ArrayList<Cat>> getCategories() {
loadCats();
return categories;
}
private void loadCats() {
dbCategories = FirebaseDatabase.getInstance().getReference("categories");
dbCategories.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NotNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
ArrayList<Cat> categoriesModel = new ArrayList<>()
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.getKey();
categoriesModel.add(new Cat("Name", 1));
}
categories.setValue(categoriesModel);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
This should work . Also you have to handle Error state with data loading .
Go through This thread to handle all the states.
I'm creating an app in Android Studio, which connects to Firebase realtime database. In the database I have the following structure:
First thing: I would have preferred a structure like:
users -> email -> {23, 13, 4, .., 5} but i found out that with Firebase I must have a pair key - value so I can't get this kind of structure. Am I right?!
Anyways.. I created a class like this:
public class ItemModel {
private int itemImg;
private int deleteFav;
private String itemLine;
public ItemModel(){}
public ItemModel(String itemLine) {
this.itemLine = itemLine;
}
public ItemModel(int itemImg, String itemLine, int deleteFav) {
this.itemImg = itemImg;
this.deleteFav = deleteFav;
this.itemLine = itemLine;
}
public int getItemImg() {
return itemImg;
}
public int getDeleteFav() {
return deleteFav;
}
public String getItemLine() {
return itemLine;
}
#Override
public String toString() {
return itemLine;
}
}
And this is my Firebase Database Helper class:
public class FirebaseDatabaseHelper {
private FirebaseDatabase firebaseDatabase;
private DatabaseReference databaseReferenceFavorites;
private List<ItemModel> favouriteList = new ArrayList<>();
private FirebaseAuth mAuth;
// In order to link our process we need to create interface
public interface DataStatus {
void DataIsLoaded(List<ItemModel> favourites, List<String> keys);
}
public FirebaseDatabaseHelper(){
mAuth = FirebaseAuth.getInstance();
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReferenceFavorites = firebaseDatabase.getReference("users");
}
public void readFavoriteLines(final DataStatus dataStatus){
databaseReferenceFavorites.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) { // asincrono
favouriteList.clear();
List<String> keys = new ArrayList<>();
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
keys.add(keyNode.getKey());
ItemModel favourite = keyNode.getValue(ItemModel.class);
favouriteList.add(favourite);
}
dataStatus.DataIsLoaded(favouriteList, keys);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
static String encodeUserEmail(String userEmail) {
return userEmail.replace(".", ",");
}
}
When I run, from this class i get the error "No setter/field for test#email,com found on class com.example.x.y.ItemModel". I read other people having this error here but can't understand which part of my code is not ok. I tried to add setters and to change names of "v1" in database to "itemLine" but still having the same error.
The thing is that actually my item appear in the UI when I run but it miss one data, the itemLine. The row must be img1 - itemLine - img2 but it shows only img1 - nothing - img2. I need to take only the value of each test#email,com (itemLine) and put this value (23 for example) in my RecyclerView item. The row should look like this:
This will show nothing because you're trying to get value from users not test#email,com
Try this
Instead of this
databaseReferenceFavorites = firebaseDatabase.getReference("users");
this should fetch your data
Create database reference to the location
public FirebaseDatabaseHelper(){
mAuth = FirebaseAuth.getInstance();
firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference databaseReferenceFavorites =
firebaseDatabase.getReference("users");
DatabaseReference databaseReferenceitemline =
databaseReferenceFavorites.child("test#gmail,com")
}
public void readFavoriteLines(final DataStatus dataStatus){
databaseReferenceitemline.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) { // asincrono
favouriteList.clear();
List<String> keys = new ArrayList<>();
for (DataSnapshot keyNode : dataSnapshot.getChildren()){
keys.add(keyNode.getKey());
ItemModel favourite = keyNode.getValue(ItemModel.class);
favouriteList.add(favourite);
}
dataStatus.DataIsLoaded(favouriteList, keys);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
static String encodeUserEmail(String userEmail) {
return userEmail.replace(".", ",");
}
}
In this snippet
databaseReferenceFavorites points to user
databaseReferenceitemline points to test#gmail,com
I have a button which updates the int data value in database but I want to do an addition of a value to an existing integer data in Firebase Realtime Database not just by replacing it with another value.
The current integer value is 400 in the child of "points". I wanted to add a number to it and then update it.
For example, if I add 200, it will update the data inside the firebase and then display 600 there.
Would really appreciate if anyone can help me with this?
Main code:
Button btnDone;
DatabaseReference DBR;
int z = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tapcard);
btnDone = findViewById(R.id.buttonDone);
DBR = FirebaseDatabase.getInstance().getReference().child("Member");
btnDone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DBR.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
int count = (int) dataSnapshot.getChildrenCount();
for (z = 1; z < count + 1; z++) {
DBR = FirebaseDatabase.getInstance().getReference().child("Member").child(String.valueOf(z));
DBR.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getRef().child("points").setValue(100);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Intent i = new Intent(TapCardActivity.this, HomeActivity.class);
startActivity(i);
}
});
}
Rewards class:
public class RewardsClass implements Serializable {
private String Name;
private String Description;
private int img;
private int points;
public RewardsClass(String name, String description, int img, int points) {
Name = name;
Description = description;
this.img = img;
this.points = points;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public int getImg() {
return img;
}
public void setImg(int img) {
this.img = img;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
}
The easiest way to add a value to a property in the Realtime Database is by using the (pretty new) increment() operation.
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userRef = rootRef.child("Member").child(String.valueOf(z));
userRef.child("points").setValue(ServerValue.increment(200));
Also see:
How quickly can you atomically increment a value on the Firebase Realtime Database?
this is a picture of firebase datathis is the image of log which i am getting in logcat
mDatabase=FirebaseDatabase.getInstance();
mRef=mDatabase.getReference("items").child("0").child("snippet");
mChildEventListner = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
for (DataSnapshot Snapshot : dataSnapshot.getChildren()) {
CategoriesModelClass user = dataSnapshot.getValue(CategoriesModelClass.class);
Log.d("kkk", "" + user);
title_description.add(user);
}
categoriesRecycleView.notifyDataSetChanged();
}
This is my code from activitymain and I don't know should I fire query for title and description or it it will fetch it from the for loop?
this is the code of my model class
public class CategoriesModelClass {
String title,description;
public CategoriesModelClass(){
}
public CategoriesModelClass(String title, String description) {
this.title = title;
this.description = description;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public void setTitle(String title) {
this.title = title;
}
public void setDescription(String description) {
this.description = description;
}
}
and i am try to set this data in my recycle view i need only title and description
To get the values of description and title, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference snippetRef = rootRef.child("items").child("0").child("snippet");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
CategoriesModelClass user = dataSnapshot.getValue(CategoriesModelClass.class);
Log.d("kkk", "" + user.getTitle());
//Get the values out of the user object
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore errors!
}
};
snippetRef.addListenerForSingleValueEvent(valueEventListener);
See, there is no need to loop over the snippet node, and this because we need to get the data according to type of object that is stored.
If there will be more than one items in the 0 node, then please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference zeroRef = rootRef.child("items").child("0");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
CategoriesModelClass user = ds.getValue(CategoriesModelClass.class);
Log.d("kkk", "" + user.getTitle());
}
//Get the values out of the user object
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore errors!
}
};
zero.addListenerForSingleValueEvent(valueEventListener);
I'm working on getting a simple messaging system working using Firebase. But this one thing is causing me to want to pull out my own hair. I have a map that I'm using to store <String,Message> pairs, where Message is a class I wrote. I can't get my messages out of the map though. I've isolated the problem to be with map.get(key) not returning the Message, even though map.containsKey(key) returns true. What could be causing this and how do I fix it?
Here's the Message class:
public class Message {
private long timeStamp;
private String message;
private String to;
private String from;
public Message(String message, String to, String from)
{
timeStamp = new Date().getTime();
this.message = message;
this.to = to;
this.from = from;
}
public Message(){
}
public String getMessageText() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public String getTo() {
return this.to;
}
public void setTo(String to) {
this.to = to;
}
public String getFrom() {
return this.from;
}
public void setFrom(String from) {
this.from = from;
}
public long getTimeStamp() {
return this.timeStamp;
}
public void setTimeStamp(long timeStamp) {
this.timeStamp = timeStamp;
}
}
This is the code I used that showed me map.containsKey(key) returns true:
public class LoadMessages extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_messages);
// Load previous messages
final LinearLayout messagesLayout = (LinearLayout) findViewById(R.id.messagesLayout);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = database.getReference(getIntent().getStringExtra("user") + "/Messages");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Map<String, Message> map = new TreeMap<String, Message>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Message m = snapshot.getValue(Message.class);
map.put(String.valueOf(m.getTimeStamp()), m);
TextView TV = new TextView(LoadMessages.this);
Boolean ck = map.containsKey(String.valueOf(m.getTimeStamp()));
if (ck) {
TV.setText("Contains key");
} else {
TV.setText("Doesn't contain key.");
}
messagesLayout.addView(TV);
}
// code to iterate through map entries and display messages
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// code Add new message onClick of fab
}
}
And this version of the code shows nothing in the TextView:
public class LoadMessages extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_load_messages);
// Load previous messages
final LinearLayout messagesLayout = (LinearLayout) findViewById(R.id.messagesLayout);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference databaseReference = database.getReference(getIntent().getStringExtra("user") + "/Messages");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
Map<String, Message> map = new TreeMap<String, Message>();
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Message m = snapshot.getValue(Message.class);
map.put(String.valueOf(m.getTimeStamp()), m);
TextView TV = new TextView(LoadMessages.this);
Message test = map.get(String.valueOf(m.getTimeStamp()));
TV.setText(test.getMessageText());
messagesLayout.addView(TV);
}
// code to iterate through map entries and display messages
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// code Add new message onClick of fab
}
}
Edit: Here's my database structure:
I think the problem is that snapshot.getValue(Message.class) returns null.
TreeMap can store null as a value, so while it contains your key the value is actually null.
Okay, I figured it out! It turns out that the message String in Message was being changed to messageText in the database, so when I tried to extract it into a Message object it wouldn't recognize it. The fix was to change the message String in the Message class to messageText.