I am working on Firebase to retreive data using addValueEventListener from Android SDK but i found sometime the response time take minimum 1 minute to get the result.
My Code :
Firebase firebase = new Firebase("https://example.firebaseio.com/");
firebase.child("XYZ").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("DataFirebase","onDataChange : "+dataSnapshot);
Toast.makeText(getApplicationContext(),"onDataChange",Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Log.d("DataFirebase","onCancelled : "+firebaseError);
Toast.makeText(getApplicationContext(),"onCancelled",Toast.LENGTH_SHORT).show();
}
});
This is my above code , please let me know , how can i get the result instantly from a key. Please suggest me some solution.
I too have a problem of slowness with firebase realtime db. Try calling, FirebaseDatabase.getInstance().setPersistenceEnabled(true); inside your Application class's "onCreate" method.
Be aware that this will save data on your device and the second call and above will be much faster but from cache and can be outdated, Read this for handling syncing data from server when needed immediately.
Related
First time listener firing takes so much time (approx. 40s), subsequent loads takes lesser time (approx. 1s), how can speed up the first time load as well?
I have given,
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
on start of the activity.
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("");
ref.keepSynced(true);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
If you are using a listener, you need to know that you are trying to read data over the internet. You cannot compare this with an atempt to read a SQLite database, which is stored locally on disk. The speed of getting the data from Firebase servers, depends on the speed of your internet connection and on the ammount of data that you are trying to get. So most likely the reason for waiting so much is one of this. If the reason is the ammount of data, try to optimize your queries or try to get the data in small parts.
If we are speaking abot the first atempt to read a record, it might be slower than the subsequent ones, because it has to initiate the internet connection. I know that Firebase team is trying to improve the performance, but you can't expect 0ms when retrieving data over a network.
According to your comment, I need to tell you a few more things. There is no way to force the retrieval of the data from the cache while you're connected to the server, as you cannot to stop the retrieval of the data from the cache while you are not connected to the server.
Firebase is desinged to retrieve data from the chache when the device is permanently offline or while your application temporarily loses its network connection and you cannot change this behaviour.
Edit:
So to get the FirebaseDatabase object you need to use the following line of code once:
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
Then to get a DatabaseReference, you need to use the following line.
DatabaseReference rootRef = firebaseDatabase.getReference();
I'm sure you'll need to in your activity more then one reference. Let's say you'll use two:
DatabaseReference usersRef = rootRef.child("users");
DatabaseReference postRef = rootRef.child("post");
You can now add a listener for on each one of these references like this:
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//code to get the data
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);
And the code the remove the listener is as explained in my answer from this post.
Don't forget, onDestroy() is not always called.
As a conclusion, you create a single database connection, use as many references you need, add the listeners accordingly, remove then according to the life-cycle of you activity.
My Firebase database still have slight downloads even after goOffline() and keepSynced(false).
I just want to get the data once. Then I save it to SharedPreferences. Next time user run the app it will check if the data exists in SharedPreferences, if it does then no need to get from Firebase again.
But in the Firebase dashboard I keep on seeing increased ammount of downloads (like 10KB) after some couple hours.
How do I completely turn off this Firebase? Am I missing something?
MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
---- SOME PSEUDO CODE ----
if (mySharedPreferences.has(theValue)) {
//already has the value.
//No need to get from Firebase.
}
else { //doesn't have the value, so get it from Firebase.
FirebaseDatabase.getInstance().goOnline(); //-->ONLINE
DatabaseReference myRef = FirebaseDatabase.getInstance().getReference("someNode");
myRef.child("datax").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
mySharedPreferences.set(theValue);
FirebaseDatabase.getInstance().goOffline(); //-->OFFLINE
}
#Override
public void onCancelled(DatabaseError databaseError) {
FirebaseDatabase.getInstance().goOffline(); //-->OFFLINE
}
});
myRef.keepSynced(false); //-->NOT SYNCYED
}
}
You cannot completely turn off Firebase as long as you use are using the database. What can you see in Firebase Console is traffic that is gathered from all sources. Even if you have active listeners or only the users are accessing your app, all that traffic is recorded there. Even the usage of Firebase Console is considered usage and is present as traffic there. As Frank said, to have a more details view about your traffic you need to enable debug logging and check what happens in the logcat.
There's a Firebase database associated with my project. When the value changes to 2 then after 10 minutes I want the same field to update to 1. The project is on android.
Is there any way to do it? For creating a specific time interval?
I would suggest you to write a JavaScript function which writes the new value after 10 minutes, and write a Firebase write event trigger to call that function whenever you see a change in value and the value as 2.
If you write this functionality in Android App, it may not update in time if the user disconnects the internet from his phone.
Documentation for Firebase Function
Read this documentation. It is fairly easy and an integral part of Firebase as a backend for Applications.
You could do this with Cloud Functions for Firebase, or alternatively with a timer in Android:
final DatabaseReference ref = ...;
ref.addListenerForSingleValueEvent(new ValueEventListener() {
void onDataChanged(DataSnapshot snapshot) {
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
ref.set(1);
}
},
10*60*1000);
}
...
Inspired by What is the equivalent to a JavaScript setInterval/setTimeout in Android/Java?
I'm wondering on Android, how the underlying actual mechanism work when you add an listener to the database. Is it just more frequent pulling or something else special?
Update:
To make it clearer, I understand what a listener is, but I meant how does the 'listening' scheme work, how a client (Android) knows the data on the server changed. Is it just a periodical pulling? (and Firebase engineers already do the hard work to cover that and make it easy for us).
Looks like firebase is not open-source.
// Attach an listener to read the data at our posts reference
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
disclaimer: this is a simplified description of how things work at the time of writing. Things may have changed by the time your read it.
When your app connects to the Firebase Database, it opens a web socket connection from the device to a Firebase server. This connection stays open for the lifetime of your app or until you call goOffline().
When you attach a listener, the client sends the location (and potential query parameters) to the server. The server adds that listener to a list of all listeners of all connected clients. It then also sends back the initial data for that listeners.
Whenever a write operation is committed to the database, the server scans the listeners. For each relevant listener, the server sends an update to the client over the open web socket.
It happens Asynchronously
Adding listeners to a node reference will fetch any changes made to the node reference asynchronously
void onDataChange(DataSnapshot snapshot)
This method will be called with a snapshot of the data at this location. It will also be called each time that data changes.
void onCancelled(FirebaseError error)
This method will be triggered in the event that this listener either failed at the server, or is removed as a result of the security and Firebase rules. For more information on securing your data, see: Security Quickstart
Example
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
Users users = snapshot.getValue(Users.class) //This is your POJO class
String name = users.getName(); //Other getter methods to fetch data from firbase
}
#Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
It's explained in the guide Firebase - Retrieve Data on Android
This method is triggered once when the listener is attached and again every time the data, including children, changes.
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.