Firebase database still have slight downloads even after goOffline() and keepSynced(false) - android

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.

Related

Android firebase taking approx 30 second to load data first time [duplicate]

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.

Firebase Database: apparently rules do not apply if client is offline?

Consider the following example:
I'm writing a value on a test/ node, and I have set up a rule, that will allow the write, only if the "(new value) equals (old value + 1)", that is newData.val() == data.val() + 1
Let's say that the initial value of the test/ node is 0.
If the client goes offline and executes the following commands:
testRef.setValue(1);
testRef.setValue(2);
testRef.setValue(3);
testRef.setValue(4);
testRef.setValue(5);
Then when he goes back online, the value 5 will be written in the database, but I'm not sure I understand why, since 5 != 0 + 1. I guess that this happens due to the caching of the previous values in the local database, but unfortunately that's not the result I am trying to achieve. I want the server to reject that value since it doesn't follow the rules of the database.
Is there a way to achieve that?
Or is there any other workaround so that I can implement the following:
testRef.setValue(1); -> write value to local database -> check if value follows the rules of the online database -> if the value does not follow the rules or if we can't check that because we are offline, then delete the value from the local database
I assume that for your question "offline" means the client has no connection. In my testing, I simulated that by enabling Airplane Mode.
Firebase offline capabilities are described in the user guide. One detail provided there that is important to your question is:
The Firebase Realtime Database client automatically keeps a queue of
all write operations that are performed while your app is offline ...
When the app regains connectivity, all of the operations are sent to
the Firebase Realtime Database server.
You can see this behavior using the code below, which adds a completion listener to the setValue() calls. In my test, I put the device into Airplane Mode (offline), ran the code, and then disabled Airplane Mode to go back online. A log message is generated for each setValue(), confirming that the write operations were queued and sent when a connection was re-established. This explains why the writes satisfy your validation rule: the client does not send one write request with the final value 5, it sends five requests with the original incrementing values.
You can confirm that the rule works by running the test again without first resetting the value of test back to 0. Each write will fail.
This code also demonstrates how the Firebase client handles changes made when the client is offline, and which are later rejected by security rules. While offline, the change is made in the client cache and the onDataChange() callback fires with the new (unvalidated) value. Later, when the client goes online and the change is rejected by the server, onDataChange() fires again with the previous value.
final DatabaseReference ref = FirebaseDatabase.getInstance().getReference("test");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "onDataChange: test=" + dataSnapshot.getValue(Integer.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
final DatabaseReference.CompletionListener completionListener =
new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError == null) {
Log.d(TAG, "setValue() Success");
} else {
Log.d(TAG, "setValue() Failed " + databaseError.getMessage());
}
}
};
ref.setValue(1, completionListener);
ref.setValue(2, completionListener);
ref.setValue(3, completionListener);
ref.setValue(4, completionListener);
ref.setValue(5, completionListener);

How firebase listener actually work?

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.

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 addValueEventListener response time little slow?

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.

Categories

Resources