So I have firebase initialised in my acitivity.
mFirebase = FirebaseDatabase.getInstance();
mDatabaseReference = mFirebase.getReference("buses");
mBusReference = mDatabaseReference.child(mSelectedBusModel.getRegistrationNo());
mValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
...
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e("Data", "Cancelled");
databaseError.toException().printStackTrace();
}
}
mBusReference.addValueEventListener(mValueEventListener);
I have a singleton that extends Application and inside the onCreate method I have enabled firebase persistence:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Now my problem is when I go offline and reopen my activity the data has not been cached, nothing loads. I have read the docs and done everything mentioned but it still does not work.
What I want to do is enable my app to cache data already loaded from firebase so it's always available even after the app has been closed and re-opened.
Please note no errors are displayed in my console.
Just using setPersistenceEnabled(true) doesn't cut it. You must change your listener because you save the data in your disk but you dont handle them. You must use something like this (it was taken from firebase documentation i have used it for my app and worked for me).
--- edit ---
If you want to keep your data synced you must use ref.keepSynced(true);. The below piece of code is what i used to retrieve cached data from reference. When i am offline the child returns the values normally.
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("user");
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, String previousChild) {
System.out.println(snapshot.getValue());
}
});
Related
I'm using both Google Firebase and Room Database to store Event objects I have created, containing all the details of a given event. I use Firebase for online storage and user interaction, and I use Room Database for an easier, persistent RecyclerView implementation.
My problem is that my function for populating the Room Database with events in the user's radius doesn't seem to execute at all in NEITHER an asynchronous task NOR a Room Database callback that overrides the onCreate method. The function was fully debugged while it was used on the main thread, so I think the reason why it isn't working right now has to do with my lack of understanding of how asynchronous tasks work.
Here is my function, currently within the onCreate method of the Room Database class:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference().child("events").child("eventid");
if (ref != null) ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Event event = dataSnapshot.getValue(Event.class);
if (event != null) {
LatLng user_location = new LatLng(current_user.get(0).getLatitude(),
current_user.get(0).getLongitude());
LatLng event_location = new LatLng(event.getLatitude(), event.getLongitude());
int distance_preference = current_user.get(0).getDistance();
double distance_between_user_and_event = SphericalUtil
.computeDistanceBetween(user_location, event_location) / 1609.344;
if (distance_between_user_and_event <= distance_preference) {
eventDao.insert(event);
}
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
In an asynchronous task, I can't really debug it since it isn't on the main thread (unless I don't know how lol), and this code doesn't seem to execute at all when in the onCreate method for Room Database. There's obviously something I'm missing here.
Also, it's worth saying that my EventDao, EventDatabase, and EventRepository have all been fully debugged. I can use all of them perfectly fine at runtime -- it's just this early population task that isn't working!
Thanks so much for any help!!
Similar project created by me which uses
Firebase authentication to login user
Save and cache user notes to
sql lite database with Room
Save user notes to firebase base
database
✍️ Simple Note Making App use Sqllite Room 🧰 for caching the notes and 📥 Firebase Database for online storage
https://github.com/LanguageXX/Simple-Note-App-with-Online-Storage
Hope that helps you
i am building a app using firebase that requires an admin page and in it i want to make a list of all the usernames of users registered in the system and i am using this code:
Usernames = new ArrayList<>();
usersdb = FirebaseDatabase.getInstance().getReference().child("Users");
usersdb.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot user:dataSnapshot.getChildren()) {
Usernames.add(user.child("username").getValue().toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
adp = new ArrayAdapter<String>(context,android.R.layout.simple_list_item_1,Usernames);
lv.setAdapter(adp);
and for some reason nothing shows up in the list view in the end anyone knows why?
and my data structure looks like this:(the random letters are user uids)
Users
----sdfbsif
-----------email
-----------username
-----------password
----djgsvnv
-----------email
-----------username
-----------password
You're calling setAdapter() before the data is available from your listener. addValueEventListener is asynchronous and returns immediately, which means you're passing an empty list to the adapter. Put log messages throughout your code to see the order in which it's executing.
Instead, you could call setAdapter in the callback after all the data from the snapshot is available.
is there any ways to read data from Firebase once the Activity is loaded. At this moment I am using the regular valueEventListener, but in order for it to work, there has to be some sort of a change in the database
mDatabaseReference.child("Users").child(mUser.getUid()).
child("Posts").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
arrayOfQuestionForms.clear();
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
QuestionForm tempQuestionForm = postSnapshot.getValue(QuestionForm.class);
arrayOfQuestionForms.add(tempQuestionForm);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
What I am looking for is some way to read data from Firebase without using listeners. I have looked at other similar posts but I don't think there is a clear answer for this yet.
There is no way for reading data from a Firebase database without using listeners. Everything is about listeners when it comes to Firebase. It's true that when setting a value, we just need to use a method named setValue() directly on the reference. Unfortunately, there is no method within Firebase, let' say getValue(), which acts in the same way as setValue().
To solve this, i recommend you using addListenerForSingleValueEvent.
Add a listener for a single change in the data at this location. This listener will be triggered once with the value of the data at the location.
in order for it to work, there has to be some sort of a change in the database
This is not true and a common source of confusion for developers.
With your current code, Firebase will immediately start reading the data from the server. Once it gets that data, it invokes your onDataChange().
From the documentation:
This method is triggered once when the listener is attached and again every time the data, including children, changes.
for such purpose I used different kind of listener - ChildEventListener. It has different #Override methods. The method onChildAdded returns every child-nodes of the node when called first time (i.e. on activity start).
Put attention - maybe you will need to slightly change the reference to DB (trim back one hierarchy level), to point to the parent node. If you expanded snapshot of your DB structure, I can look.
Here is updated code (sorry is made any typo - I couldn't test it as have no your DB :)
mDatabaseReference.child("Users").child(mUser.getUid()).child("Posts").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
arrayOfQuestionForms.clear();
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
QuestionForm tempQuestionForm = postSnapshot.getValue(QuestionForm.class);
arrayOfQuestionForms.add(tempQuestionForm);
}
}
#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) {
}
});
I keep getting the old values (which no longer is in the database) from my Firebase database. Here is how the database looks right now:
I am getting the info under friendlist. It used to be only one child there with key-value set soosk: true, but now it looks like in the photo. When using addListenerForSingleValueEvent() to my databaseRef, the friendlist retrieved only has soosk: true in it. Here is my code:
mFirebaseDatabaseReference = FirebaseDatabase
.getInstance()
.getReference(
"users/"+FirebaseAuth.getInstance().getCurrentUser().getUid()
);
mFirebaseDatabaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
Log.d(TAG, user.getFriendlist().toString());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The method you need to use to have all the values updated is addValueEventListener(). Because you need to listen for more than one value this is the only way to achieve it and to use addListenerForSingleValueEvent().
The most important thing is to remove the listener in your onDestroy method like this:
yourReference.removeEventListener(valueEventListener);
I just started using firebase and I'm amazed of how simple are complex things, and how complex simple things can be.
I need to check if a user exists in my Firebase database, and if exists, I need to get its key and value.
I have the key and I try to find it in the DB by going to my user subtree and loking for a child with the same key (ID)
DatabaseReference root_firebase = FirebaseDatabase.getInstance().getReference();
DatabaseReference users_firebase = root_firebase.child("Users");
DatabaseReference friend_found = users_firebase.child(key_searched_friend);
once I have it I try to call some method like
friend_found.getValue();
or
friend_found.child("user_name").getValue();
But it does not exist,
this seems weird since I can do both
friend_found.getKey();
friend_found.child("user_name").getKey();
I can't do this with the overriden method onDataChanged() since the data does not change when I query for this value.
This is my firebase database structure:
{
"RoomNames" : {
"Room-KM5cof0jcoMN8a4g6vC" : {
"room_name" : "TESTrOOM"
},
"Room-KM5dg_WPRdEOT4_oJ1r" : {
"room_name" : "testRoom2"
}
},
"Users" : {
"User-KM5ZaGq0xvjQis05CPF" : {
"user_name" : "Enrique"
}
}
}
You say: I can't do this with the overriden method onDataChanged() since the data does not change when I query for this value
The guide for how to Retrieve Data explains that:
Firebase data is retrieved by attaching an asynchronous listener to a
FirebaseDatabase reference. The listener is triggered once for the
initial state of the data and again anytime the data changes.
So when you attach a listener to a location, onDataChanged() fires and gives you the current value.
In the section titled Read Data Once, the guide states:
In some cases you may want a callback to be called once and then
immediately removed, such as when initializing a UI element that you
don't expect to change. You can use the
addListenerForSingleValueEvent() method to simplify this scenario: it
triggers once and then does not trigger again.
Use as below :
friend_found.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG,"Error while reading data");
}
});
For a database reference object, the same way one can add an event listener, it can also be removed, using removeEventListener.
Instead of creating an anonymous object like this
friend_found.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG,"Error while reading data");
}
});
you can create a named object of ValueEventListener and remove it from the database reference object using removeEventListener, at the end of the onDataChange method
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String value = dataSnapshot.getValue(String.class);
friend_found.removeEventListener(valueEventListener);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.e(TAG,"Error while reading data");
}
});
friend_found.addValueEventListener(valueEventListener);
The code inside onDataChange method gets executed only once as the ValueEventListener object is removed as soon as the last line of the method gets executed.