Firebase last action time in specified location - android

I keep a local copy of a simple database in user's phone. This way the app can be used offline. I want to check with firebase server from time to time and update the local database if there is any change. So I need to know last action (insert, update, delete, etc.) time in a specified location in Firebase database. Is that possible? Or should I implement my own mechanism?

The Firebase Database does not store informations like the timestamp for CRUD operations that are performed. Because of that, you need to store this kind of data yourself with your own mechanism. So, you need to create a new field for each child you want to trace and change the value of the TIMESTAMP every time a action is performed. The best practice is to save your data as a TIMESTAMP like this: ServerValue.TIMESTAMP. Note, that when you are saving the TIMESTAMP, you are saving as a Map and when you are retrieving, you are retrieving it as a long. To set the TIMESTAMP, i recomand you using the following code:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
Map map = new HashMap();
map.put("time", ServerValue.TIMESTAMP);
ref.child("yourNode").updateChildren(map);
To get you data back, i recomand you using the following method:
public static String getTimeDate(long timeStamp){
try{
DateFormat dateFormat = getDateTimeInstance();
Date netDate = (new Date(timeStamp));
return dateFormat.format(netDate);
} catch(Exception e) {
return "date";
}
}

This is possible but you shouldn't
Firebase already has offline capabilities, is very simple to use. Is a 2 steps process:
Set offline capabilities on
Set what you want to keep track ass offline
This is the official documentation
In code this is done something like this:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");
scoresRef.keepSynced(true);
There is big temptation to use:
FirebaseDatabase.getInstance().getReference().keepSynced(true);
Trying to keep everything sync by syncing the root reference doesn't work, you have to be specific, at least at 1 level parent.
The syncing when the connection is resumed is automatic, the user has to open the app though, flawless.
Now, if you still insist on doing this, then what you have to do is set ServeValue.TimeStamp
In the same link provided above, you can find how to set the server timestamp, here is the direct reference.
Later you can sort by that timestamp, here is a more detailed answer

Related

How to notify user that new data is avalable so that they need to refresh?

I'm working on a news app. I fetch data from server directly in JSON format, parse it and show in views. I would like to be able to be able to notfify the use that new data is avaible and they need to refresh instead of automatically updating.
How can I achieve this ?
The simplest way would be to compare the json data string value to the new value from the server. Something like this:
if (currentJSONDataString != newJSONDataString) {
Toast.make(context, “Updates available. Please refresh”, Toast.LENGTH_SHORT).show()
}
The limitation here though is that this only checks to see if your current data differs in any way from the server data. If you had things in your data model such as a datetime field that indicated the last updated at time or something similar you could do a more accurate comparison to check if the current data is before the newer data.

Insert a timestamp of data insertion into database

I want to add a timestamp of a data entry creation, example:
myRef.child("uid").setValue(data);
//add timestamp to the same path myRef.child("uid").setValue(<timestamp here>)
What would be the best timestamp, so that it will be independent of any time zone? (For example if a user's phone clock is set to the wrong time)
I did see this article from Firebae docs: Timestamp, but can't figure how to use it.
Use the value placeholder firebase.database.ServerValue.TIMESTAMP to update a value with the current clock time on the server at the time of the write, as seen by the server. It's a token value that means nothing on the client but has a special meaning on the server when it's written.
inside Firebase Functions transform the timestamp like so:
timestampObj.toDate()
timestampObj.toMillis().toString()
documentation here https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp

Does a local Android Firestore instance sync its internal clock with the server?

The reason I ask is because we know that local writes to Firestore are instant. Meaning that locally written objects can be queried instantly. We are also told by the documentation that there is a ServerTimestamp annotation.
ServerTimestamp
public abstract #interface ServerTimestamp implements Annotation
Annotation used to mark a timestamp field to be populated
with a server timestamp. If a POJO being written contains null for a
#ServerTimestamp-annotated field, it will be replaced with a
server-generated timestamp.
It sounds like if an object field is so annotated, and the object written locally, then queried locally, then the field would contain the current server timestamp. Of course this would mean that the local Firestore instance, at some point, synced its clock with the server. Is this true?
If true, then such a trick could be used to query the current Firebase server time, effectively synching clocks.
The default behavior for server timestamps written to a document, read back before the document is synchronized, is simply a null value. You can change this behavior with ServerTimestampBehavior. Pass one if its enums to getData() to get one of the following:
ESTIMATE
Return local estimates for ServerTimestamps that have not yet been set
to their final value. This estimate will likely differ from the final
value and may cause these pending values to change once the server
result becomes available.
The estimated value is derived from what the client SDK believes to be the current time, using the local clock. When the write is fully committed, the timestamp will likely change to be the actual server value.
PREVIOUS
Return the previous value for ServerTimestamps that have not yet been
set to their final value.
It looks like Android Firestore documentation exposes the Clock Skew
Clock Skew
While firebase.database.ServerValue.TIMESTAMP is much more
accurate, and preferable for most read/write operations, it can
occasionally be useful to estimate the client's clock skew with
respect to the Firebase Realtime Database's servers. You can attach a
callback to the location /.info/serverTimeOffset to obtain the value,
in milliseconds, that Firebase Realtime Database clients add to the
local reported time (epoch time in milliseconds) to estimate the
server time. Note that this offset's accuracy can be affected by
networking latency, and so is useful primarily for discovering large
(> 1 second) discrepancies in clock time.
DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset");
offsetRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
double offset = snapshot.getValue(Double.class);
double estimatedServerTimeMs = System.currentTimeMillis() + offset;
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
});
This could be a sufficient way to sync clocks.

Firebase real-time data base, add new timestamp child node upon every login?

I'm very new to firebase as this is my first project so any help is appreciated because this problem has taken quite a few hours of my time. I think the solution could be very simple but I'm failing to see it.
I would like to collect user-specific data upon every login to the app so it'd be something like this (in the real-time database):
-user-id{
-10:40:50:{
-location:"loation1",
-activity:"walking",
-batteryLevel:"90%"
}
-11:50:30:{
-location:"location2",
-activity:"running",
-battery-level:"80%"
}
}
I have tried to start by simply making different nodes (the timestamps) for every login before I go into more details with the children of these timestamps (location, activity and battery level).
I thought the code below would create something like this:
-user-id{
-10:40:50:"10:40:50"
-11:50:30:"11:50:30"
}
But instead I only get
-user-id{
-11:50:30:"11:50:30"
}
My problem is that every time the user logs in, the new timestamp overwrites the old one so user-id always has only one child node (the timestamp associated with the latest login).
This is the code I tried. PS: I have tried replacing ".setValue()" with ".push().setValue()" but the last timestamp always erases the previous one.
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(firebaseAuth.getCurrentUser().getUid());
myRef.setValue( firebaseAuth.getCurrentUser().getUid());
String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
DatabaseReference usersRef = myRef.child(currentDateTime );
usersRef.setValue(currentDateTime);
The code above I've put it in the Oncreate of the activity "ProfileActivity.java" which is basically the activity the user is redirected to after he is correctly authenticated.
Thank you for your help.
This is a very silly mistake.
DatabaseReference myRef = database.getReference(firebaseAuth.getCurrentUser().getUid());
myRef.setValue( firebaseAuth.getCurrentUser().getUid());
These two lines of code always completely clear your node and set the value to your Uid.
If the node looked like this before
user123
- name:"peter"
- 10:40:50:"10:40:50"
it will now look like this
user123:"user123"
You set the complete content of the node to your Uid. If you just remove your myRef.setValue(...) statement, your problem will be solved.

How to add server time using FirebaseStore timestamp?

If I'm using Firebase data-base I can set server-time as below:
user.put("time", ServerValue.TIMESTAMP);
And then update it.
But if I used the same one with FireStore it doesn't succeed, Also I don't need to implement firebase-data-base in my gradle for only this purpose.
I can see that there is ServerTimestamp.class related to FireStore but I don't know how to use it.
Thanks in advance.
According to docs it would be something like this:
#ServerTimestamp Date time;
If null it will have the server-generated timestamp, so you don't need to do set the value for it.
Ref:
Annotation used to mark a Date field to be populated with a server timestamp. If a POJO being written contains null for a #ServerTimestamp-annotated field, it will be replaced with a server-generated timestamp.
(https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/ServerTimestamp)
Edit:
Or when working with a map type object directly:
DocumentReference docRef = db.collection("objects").document("some-id");
// Update the timestamp field with the value from the server
Map<String,Object> updates = new HashMap<>();
updates.put("timestamp", FieldValue.serverTimestamp());
Ref:
https://firebase.google.com/docs/firestore/manage-data/add-data#update_fields_in_nested_objects

Categories

Resources