Firebase Realtime Database - retrieving data - android

I created my firebase console project and want to use real time database. I am able to add data using my model class (On Register Activity). But now i want to retrieve the same data in my HomeActivtiy.
Firebase is only providing valueChangeListener or addValueListener. But by the time i reach HomeActivity, and set the listener. Data has already changed and my Datasnapshot return null object on onDataChanged()
I am using Firebase version 3 - android
I want to do a get request to my "users" node, where I need data instead of just Database reference. is it possible in Firebase?

Are you sure your reference is correct? If you are using an addValueEventListener on the HomeActivity then your value should also change in the HomeActivity (I assume you are getting a list of registrations).
Make your reference point to parent node of where the registrations are happening.
You can also prove yourself correct or wrong by adding an addOnSuccessListener after saving the registration data.
db.updateChildren(childUpdates).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
finish();
}
});

Related

Dealing with FirebaseUI sign-in and offline Firestore data?

I am having difficulty figuring out how user authentication/sign-in via FirebaseUI works in relation to the offline persistence of data from a Firestore database in Android.
I understand a user must be signed in in order to retrieve their documents from the database but what happens when the user is offline? How do I set up the flow of user and data checks in my app before displaying the user's list of documents, if any?
Please correct me if my understanding of the documentation (FirebaseUI and Firestore offline data) below is wrong.
So there are I think basically 3 pages a user would see:
A sign-up/sign-in page
An empty page when the user has no data in the database
A list of their documents
The first sign-up/sign-in page should be displayed for first time users and signed out users (whether the user has signed-out themselves or their sign-in token has expired). This is where FirebaseUI comes to the rescue. Can I check for both cases with just the getCurrentUser method? What does this method return when the user is offline? Have I missed this somewhere in the documentation on managing users?
The second empty page should be displayed for signed in users who don't have any data in the database (whether because they have just signed in for the first time or they have deleted all of their data). Do I use a get call to check for data? What does it return when there is no data or what listener do I have to use? Have I missed this somewhere in the documentation on getting data?
The third list page should be displayed for signed in users who have existing data or who have just created data/documents. This can be obtained with a query on a collection via a get call on that collection.
Finally, would you tie all this together from within one activity/fragment in the following way and order in onCreate/onCreateView?
First - Check for first time and signed out users: If yes then display (inflate) the first page (i.e. launch the FirebaseUI sign in intent activity). What happens after the user has signed up/signed in? Is the user brought back to the originating activity/fragment? How do I handle this?
Second - Check for data in the database: If there is no data then display an 'empty' page. If there is data then display the list of documents instead. It seems this can be handled by switching visibility between say a TextView with the text "Empty" and the RecyclerView in the same layout (see this SO post).
Please help!
Can I check for both cases with just the getCurrentUser method? What does this method return when the user is offline?
When calling getCurrentUser() method on a FirebaseAuth object it returns an object of type FirebaseUser if the authentication process is successful.
FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
But before that you need to instantiate the firebaseAuth object by calling the static FirebaseAuth.getInstance() method like this:
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
So if the authentication process is successful and you are getting offline, it doesn't matter, calling getCurrentUser() will always return the FirebaseUser object.
Do I use a get call to check for data?
Yes, you should use a get() call and first time check if (task.isSuccessful()) and second if the data exist at a particular location.
What does it return when there is no data or what listener do I have to use?
It will return an empty DocumentSnapshot object. So first you'll need to use a get() and use the addOnCompleteListener().
This can be obtained with a query on a collection via a get call on that collection.
Yes that's correct.
Finally, would you tie all this together from within one activity/fragment in the following way and order in onCreate/onCreateView?
Yes, you can tie all this together from within one activity/fragment.
What happens after the user has signed up/signed in? Is the user brought back to the originating activity/fragment? How do I handle this?
If the user signs out, you should redirect the user to the LoginActivity. I have exaplained in one of my tutorials step by step, the entire authentication process using Google and Firebase.
Check for data in the database: If there is no data then display an 'empty' page.
This is a recommended way in which you can retrieve data from a Cloud Firestore database and display it in a RecyclerView using FirestoreRecyclerAdapter. So in such case you can override the onDataChanged() like this:
#Override
public void onDataChanged() {
if (getItemCount() == 0) {
recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.VISIBLE);
} else {
recyclerView.setVisibility(View.VISIBLE);
emptyView.setVisibility(View.GONE);
}
}

Check if firebase has finished adding items to database

I am sending data from my android app to a realtime firebase database.
I would like to check when firebase has finished adding these items into the database, as I will be calling a script on the server that will access the data in the database (through an asynctask).
But before I call the script, I need to make sure that firebase has finished adding all the items as to avoid any conflicts in the data. The code would be something like this:
myRef.child(userID).setValue(items); //add items to firebase database
new SendPostRequest().execute(); //call script on the server that will connect
to firebase database and retrieve data.
I was wondering if the script would be called whilst firebase is adding data to the database therefore it would retrieve partial data, so I need to make sure that firebase has finished adding the items into the database first.
You can add a completion listener to setValue() to get notified when the call has completed.
See the section add a completion callback in the Firebase documentation for a full example.
mDatabase.child("users").child(userId).setValue(user)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
// Write was successful!
// ...
}
})
...

Firebase - Access data without Callback

I want to get the data stored in the DB without being restricted to access it only when there is a data change.
I've seen this post from 2016:
How to access Firebase data without using addValueEventListener
Which suggested to use addValueEventListener.
I've also seen this post:
Accessing data in Firebase databse
Without good answer.
ValueEventListener will trigger the onDataChange only when the database will have a change.
How else can I access the database without something being changed in the database?
For now I will write simple harmless change in order to access the data, but i'm wondering if it's the only way to do it.
Thanks
Of course this is absolutely not true. You can retrieve data whenever you like to.
Firstly I would like to advice you to read this documentation reference.
Secondly I provide you with what you really asked for.
If you read the documentation you will notice that it states the following:
The onDataChange() method in this class is triggered once when the listener is attached and again every time the data changes, including the children.
That means that with this code:
databaseReference.removeEventListener(eventListener);
With that method you would be able to detatch any listener so it only listens once or detatch it whenever you want to.
There is a method for only retrieving data once though.
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "Data retrieved.");
}
...
}
This method will exactly call onDataChange once or respectively onCancelled.

Firebase on Android - how to make event handler for data retrieval fire when I need it to?

I am new to Firebase and need some help with a query to retrieve data from a table. I am currently able to access and retrieve the data that I need from firebase, however, the timing is the problem I am having an issue with.
From everything I've seen, the firebase database requires me to add event listeners to the Query or DatabaseReference objects. I am trying to download the contents of a node called "questions" before a method to display the question contents is called, however, I cannot control the timing of the firing of the event which downloads the data, and as a result my display method is always called before the firebase event fires.
How can I execute a query when I want, and be sure it will be completed before a certain section of my code executes? I am used to traditional RDBs where you execute a query and get its results and then move forward with your logic. The need to use an event handler with firebase is what I am having a hard time with. I have even tried moving the definition of the firebase reference object and the event handler into onCreate() and moved the code that calls my display method into onStart() without any success - same problem. The data I am trying to get does not change so I only need to download it once at the beginning to have available for the display method.
Here is an image of my "questions" node which is a child of the root.
image of the child "questions" node on my firebase DB
Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get Firebase DB reference
firebase = FirebaseDatabase.getInstance();
fdbRef = firebase.getReference("questions");
// [START Question_event_listener]
fdbRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Questions object and use the values to update the UI
objQuestions = dataSnapshot.getValue();
Log.w("Firebase:", "In Firebase ValueEventListener");
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Questions failed, log a message
Log.w("Firebase Error:", "onCancelled:", databaseError.toException());
Toast.makeText(ReviewActivity.this, "Failed to load question!", Toast.LENGTH_SHORT).show();
}
});
//. . . remaining onCreate logic removed for simplicity
} //end of onCreate
#Override
public void onStart() {
super.onStart();
// I moved this logic from onCreate to onStart but did not help...
// Firebase retrieve must execute before I call any of these
if (list_type == MainActivity.LIST_UNREVIEWED_DOCS)
displayNewReviewForm();
else if (list_type == MainActivity.LIST_REVIEWS)
displayCompletedReview();
else // (list_type == MainActivity.LIST_DRAFTS)
displayDraftReview();
}
Other alternatives if I can't get this resolved may be to move this retrieve logic to the prior Activity in my sequence and pass the retrieved data as an extra to this activity - but that seems really silly to have to do such a thing. I would think I should be able to get data from a DB when I need it... not when it feels like giving it to me.
I appreciate any help getting me past this issue.
Your code is downloading the snapshot data containing all the data at the first go only, and with Firebase, you cannot download data timely, you can only do it through different references.
What I would suggest you to do is, to have a DatabaseReference of q01, q02 respectively and then call data as in when required.
If your Keys "q01", "q02" are static, which they are looking at the scenario. I would suggest you to have their DatabaseReferences:
question_one = firebase.getReference("q01");
question_two = firebase.getReference("q02");
question_three = firebase.getReference("q03");
//Once you have the reference, you can call their ValueListeners respectively
question_one.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Questions object and use the values to update the UI
objQuestions = dataSnapshot.getValue();
Log.w("Firebase:", "In Firebase ValueEventListener");
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Questions failed, log a message
Log.w("Firebase Error:", "onCancelled:", databaseError.toException());
Toast.makeText(ReviewActivity.this, "Failed to load question!", Toast.LENGTH_SHORT).show();
}
});
After looking at this a bit more, I came up with 2 possible solutions to the problem I had.
The first one I sort of mentioned already in my original question post, however it's not ideal in my opinion. It basically involves relocating the firebase retrieve logic to the prior Android Activity and passing the retrieved data to the Activity I need it in as an Extra. In my case the data is a HashMap so I would need to use the serialize versions of the methods to pass the serialized content to the desired Activity.
The best solution, is much simpler. I basically relocated the logic that I had in the onStart() function (which is calling my custom display methods) and moved it inside of the Firebase Event Listener's onDataChange() method, right after the call to dataSnapshot.getValue(). This ensures that I get the data before I call my display methods. This seems to be working well now.

Firebase Android - how to tell if node has been synced

I'm using Firebase for Android for the chat component of our app.
I'm having trouble figuring out how to reliably implement status updates on each chat message.
For example, showing "Sending.." when the chat is being synced with the server, and having a success feedback after sync.
I have a onChildAdded listener that supplies the messages to my adapter. However, this listener is fired immediately when each node is added locally, and I can't check the status of each node
My Current solution is to keep a set of node keys, and add keys whenever I push something to Firebase. Then on the setValue callback, I remove the node key from the set. However, this is very unreliable since the nodes can be synced when the calling activity has been destroyed, etc.
I am wondering if there is a simpler way to check if each node has been synced to the server?
Thanks!
From the Firebase documentation on writing data:
If you'd like to know when your data has been committed, you can add a completion listener. Both setValue() and updateChildren() take an optional completion listener that is called when the write has been committed to the database.
With this handy code sample:
ref.setValue("I'm writing data", new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
System.out.println("Data could not be saved. " + firebaseError.getMessage());
} else {
System.out.println("Data saved successfully.");
}
}
});

Categories

Resources