As title what I want to do is only when database had change than run notification for it but a problem is when I run app the notification appear even the data is not change
here is my code:
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.main,container,false);
result= (TextView) v.findViewById(R.id.textView3);
notificationmanager = NotificationManagerCompat.from(ct.getcontext());
if (user != null) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String post = dataSnapshot.getValue(String.class);
result.setText(post);
Notification notification = new NotificationCompat.Builder(ct.getcontext(), CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(post)
.setContentText("test")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_EVENT)
.setDefaults(Notification.DEFAULT_ALL)
.build();
notificationmanager.notify(2,notification);
}
}
#Override
public void onCancelled(DatabaseError error) {
}
});
}
else
{
Toast.makeText(getActivity(),"not yet login",Toast.LENGTH_LONG).show();
}
return v;
}
Save the value in your local preferences, then on next change, verify if the value if it is really changed by comparing with previously saved value.
You need to use addValueEventListener(), from the docs:
public ValueEventListener addValueEventListener (ValueEventListener listener)
Add a listener for changes in the data at this location. Each time time the data changes, your listener will be called with an immutable snapshot of the data.
Using addValueEventListener, everytime there is a change in the database it will be triggered.
From #mikasaloli's explanation, I suspect the problem lies more in in a mix of the way firebase RTDB( realtime database) / Firestore functions and the wrong listener.
The first problem is, firebase RTDB/firestore by default keeps a local cache copy of the references( not all of them) you've accessed on your phone. From their docs, they say, and I quote:
"Asynchronous listeners: Data stored in a Firebase Realtime Database is retrieved by attaching an asynchronous listener to a database reference. The listener is triggered once for the initial state of the data and again anytime the data changes. An event listener may receive several different types of events. This mode of data retrieval is supported in Java, Node.js and Python Admin SDKs."
What you need to do is bypass the local cache when reading data for the first time after app startup.
here's how I've been able to do that( with some slight tweaking)
The second problem is as previously mentioned by the others, addListenerForSingleValueEvent will get triggered only once. So, assuming you receive the notification change for the first time, your listener will automagically unregister itself implying you won't receive the subsequent onDataChange events.
Now, conjecturing from the previous paragraphs, the problem with the above code is:
it attaches a listener for single value event. which then gets triggered with the local ( cached ) version of the data which forcibly isn't the latest state of the server database ( if the application was offline while some changes took place online). But then, upon attaching this listener, it gets triggered with the local version of the data and unregisters itself afterwards. Implying, the above code will get triggered once at most and might never get triggered during it's lifetime while attached.
What I suggest, is you bypass the local cache and use a addValueEventListener.
Related
How can I retrieve all data values from Firebase's real-time database when I load onStart event from my Android app without run any listener of Firebase?
Because I don't want to run any listener such as ("ondataChange, childAdded, childRemoved and etc ...") I don't need it.
From the Firebase documentation, the onDataChange method of the listener fires once when being attached and then every time there is a change. So, yes there is a way to fetch the data without an event. Though, this fetch would happen using listener only.
https://firebase.google.com/docs/database/android/read-and-write
Listen for value events To read data at a path and listen for changes,
use the addValueEventListener() oraddListenerForSingleValueEvent()
method to add a ValueEventListener to a DatabaseReference.
You can use the onDataChange() method to read a static snapshot of the
contents at a given path, as they existed at the time of the event.
This method is triggered once when the listener is attached and again
every time the data, including children, changes. The event callback
is passed a snapshot containing all data at that location, including
child data. If there is no data, the snapshot will return false when
you call exists() and null when you call getValue() on it.
There is no way to get the data from a Firebase real-time database or from Cloud Firestore without using a listener. Everything in Firebase is about listeners, even if you are getting data in real-time or if you are getting only once, you need to attach a listener on a particular location. Without it, there is no way you can get it.
Edit: From the official documentation regarding reading data in Android, here is a code snippet that demonstrates a social blogging application retrieving the details of a post from the database:
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Post post = dataSnapshot.getValue(Post.class);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
mPostReference.addValueEventListener(postListener);
Though, it is late to reply here, but I am choosing to post here only rather than creating another thread on this.
IMO, the basic expectation from any database is to be able to read a selected set of data which is available in DB. It does not matter whether I have to attach a listener or write a custom code.
While I understand that the added benefit of real-time DB is that it is event driven and UI does not need to wait for user to initiate an action for getting the data, but how come there is no way to retrieve data if there is a need !! I have spent hours looking for this one way to fetch data. OOh :(
If user turn off both wi-fi, 3g, 4g, and so on and reverse (no internet connection). Firebase database name child connections:(true/false)
So, when internet connections, wi-fi, 3g, 4g, and so on are off or missing, the user is offline so he can't be found.
Remember the two scenarios: Before and After. If user is offline before an other user search him, then he will not displayed in the list result, if user is off-line after an other user search him, then it will display NO MORE AVAILABLE icon on the user
Kindly some one help me for this problem.
To solve this, you can create a new node in your Firebase Realtime Database to hold all online users, so when the user opens the application, you'll immediately add his id to this newly created node. Then, if you want to check if the user is online, just check if his id exists in the list.
You can also add a new property named isOnline for each user in your database and then update it accordingly.
For that, I recommend you using Firebase's built-in onDisconnect() method. It enables you to predefine an operation that will happen as soon as the client becomes disconnected.
See Firebase documentation.
You can also detect the connection state of the user. For many presence-related features, it is useful for your app to know when it is online or offline. Firebase Realtime Database provides a special location at /.info/connected which is updated every time the Firebase Realtime Database client's connection state changes. Here is an example also from the official documentation:
DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
System.out.println("connected");
} else {
System.out.println("not connected");
}
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
});
Though this is more than a year late, to clear up the confusion. Alex's question would like to implement a live chat scenario in which each user can view everyone's online status at their ends or on their devices.
A simple solution be to create a node where all users would inject their online status each. e.g.
//say your realtime database has the child `online_statuses`
DatabaseReference online_status_all_users = FirebaseDatabase.getInstance().getReference().child("online_statuses");
//on each user's device when connected they should indicate e.g. `linker` should tell everyone he's snooping around
online_status_all_users.child("#linker").setValue("online");
//also when he's not doing any snooping or if snooping goes bad he should also tell
online_status_all_users.child("#linker").onDisconnect().setValue("offline")
So if another user, say mario checks for linker from his end he can be sure some snooping around is still ongoing if linker is online i.e.
DatabaseReference online_status_all_users = FirebaseDatabase.getInstance().getReference().child("online_statuses");
online_status_all_users.child("#linker").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String snooping_status = dataSnapshot.getValue(String.class);
//mario should decide what to do with linker's snooping status here e.g.
if(snooping_status.contentEquals("online")){
//tell linker to stop doing sh*t
}else{
//tell linker to do a lot of sh****t
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
So I am working on an app that uses firebase's firestore and was wondering if this is possible because I don't want my app to check for data that no longer exists in the server.
Example:
collectionReference.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot snapshots, FirebaseFirestoreException e) {
for (DocumentSnapshot snapshot : snapshots) {
System.out.println(snapshot.getId());
// This prints document IDs of documents that were deleted
// from the collection when the app was not running
}
}
});
Using DocumentSnapshot.exists() to filter snapshots existing only in the server does not work
More info in this page:
The initial state can come from the server directly, or from a local cache. If there is state available in a local cache, the query snapshot will be initially populated with the cached data, then updated with the server's data when the client has caught up with the server's state.
You can determine if the snapshot comes from the cache by checking its metadata.
QuerySnapshot#getMetadata() returns a SnapshotMetadata object.
SnapshotMetadata#isFromCache() returns a boolean if the snapshot is from the cache.
If you want to be notified whenever the metadata changes (so you can know if isFromCache() changes) then you have to pass options when you add the listener:
// Create options
QueryListenOptions options = new QueryListenOptions().includeDocumentMetadataChanges();
// Pass them when you add the listener
collectionReference.addSnapshotListener(options, new EventListener<QuerySnapshot>() {
// ...
});
See the docs for addSnapshotListener
I am developing a chat app in which i have to maintain the user online status and the technology i am using is firebase so how can i do that any kind of help is appreciated. Thanks in advance...
Mabz has the right idea conceptually, but I want to highlight a feature of Firebase that specifically addresses your use case.
The trouble that I had run into was updating the RealtimeDatabase with an 'Offline' status. That is, If the client (e.g. your Android app) is offline, how is it supposed to tell the database?
The Solution: Use DatabaseRef.onDisconnect() to set offline status automatically
DatabaseRef presenceRef =
FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!");
From the documentation:
When you establish an onDisconnect() operation, the operation lives on
the Firebase Realtime Database server. The server checks security to
make sure the user can perform the write event requested, and informs
the your app if it is invalid. The server then monitors the
connection. If at any point the connection times out, or is actively
closed by the Realtime Database client, the server checks security a
second time (to make sure the operation is still valid) and then
invokes the event.
A (slightly) more practical example might do something like this when your app first connects:
DatabaseRef userStatus =
FirebaseDatabase.getInstance().getReference("users/<user_id>/status");
userStatus.onDisconnect.setValue("offline");
userStatus.setValue("online");
NOTE: Please note the order of the last two "online" and "offline" status lines. Do not swap it, or else you might have "ghost users" in case the onDisconnect handler fails to register due to a disconnect itself. (which is actually a race condition problem)
Based upon the information you gave and not considering the performance or bandwidth constraints, here is a way on how I would solve this:
Using a service and a thread in the Real-Time Database:
Within the Real-Time Database, I would have an OnlineStatus thread, and then I would save child Key-Value pairs of User Ids and set to their Value to "Green" or "Yellow" or "Red"; this would give me the status as to whether the user is On-line or Away. So that would look like:
OnlineStatus
User1: Green
User2: Yellow
User3: Red
Create a Service that will check if:
The user is authenticated
The app is in the background
If the user is authenticated and the app is open, then write to the OnlineStatus thread Current User as a key and "Green" as a Value.
If the app is in the background and the user is authenticated, then do the same but "Yellow" is the Value.
Anything else should result in the color "Red". Also note that if the user signs-off, you may want to write "Red" during that operation.
So this allows every device to update Firebase Real-time Database. What remains is adding a reference to your OnlineStatus location to listen to changes through a ValueEventListener.
Hope this helps.
You can use database reference listener “.info/connected” plus disconnect method dbRef.onDisconnect() to solve the presence problem of online user.
Here is some sample code:
onlineStatus = db.getReference("users/"+user.getUid()+"/onlineStatus");
connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
onlineStatus.onDisconnect().setValue("offline");
onlineStatus.setValue("Online");
} else {
onlineStatus.setValue("offline");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
You can read more in this article on my website.
I am most concerned about Performance issue and don't want users to wait for progress.
I have a chatActivity, where i show a ListView.
Here i send a chatMessage
Chats chat = new Chats(chatBox.getText().toString(),Chats.TYPE_MINE, dt.format(now));
chat.personId = chatee.getMyId();
chat.isDelievered = Chats.DELIEVERED_NONE;
chats.add(chat);
mAdapter.notifyDataSetChanged();
Notice that Chat delievery is set to NONE Right now. So basically the message is being added to the Chat List even its not delivered yet.
Now on back thread here is what's happening
It takes few seconds to send message where i do this
boolean bool = sendMessage(m);
if (bool)
chatee.isDelievered = Chats.DELIEVERED_DONE; (MESSAGE SENT)
if (chatee.isDelievered == Chats.DELIEVERED_DONE)
{
app.mDbHelper.saveMessage(chatee); // SAVING TO DATABASE
Intent i = new Intent(Constants.REFRESH_NOTIF).putExtra("refresh",Constants.REFRESH_NOTIF);
context.sendBroadcast(i);
}
It will send a broadcast to the activity.
Now here is the problem.
Broadcast call this function
public void callUIMethodForRefresh(Intent intent)
{
String ref = intent.getStringExtra("refresh");
if (ref == null)
{
}
else if (ref.equals(Constants.REFRESH_NOTIF))
{
}
}
Here i am confused of how can I reset that previous Chat object added to my List.
Points to be noted , i can be sending messages at a very fast speed and the refresh could be called for an old message whereas a new message is already typed.
ONE way is i make a For loop and check for all the "ChatList" array for the message sent and then replace its delivery notice, but again this is very low performance incase i have 1000+ objects in the list.
Is there any way, i can attach the sqlite database with my listView adapter that automatically detects the changes and reset the listView etc and etc?
What could be the best strategies here to avoid performance issues.
I would suggest looking into ContentProviders and Loaders (specifically a CusorLoader). Combining these with a CursorAdapter, you can use the ContentProvider which inserts/deletes/updates your sqlite database and notifies your loader to reload it's dataset and update the CursorAdapter/ListView.