Android: Notify on specific value change in Firebase real-time database - java

Following is screenshot of my Firebase realtime database. How can I notify a user whenever the item worker_id is changed?
I've tried the following code, but it notifies about each type of data change. I want notification specific to change in worker_id:
private void CheckDataChange(){
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("posts");
Query query = myRef.orderByChild("workType");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d("Firebase","onDatachange");
for(DataSnapshot ds : dataSnapshot.getChildren()) {
try {
if(!ds.child("worker_id").getValue(String.class).equals("0")) {
Toast.makeText(MainActivity.this, "Request accepted", Toast.LENGTH_SHORT).show();
}
}catch (Exception ex){
Log.e("Firebase",ex.getMessage()+ex.getCause());
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("Firebase", databaseError.getMessage());
}
};
query.addValueEventListener(valueEventListener);
}

There is nothing built into Firebase to raise an event only when the worker_id in your current structure changes.
The most common way to implement something like that would be to create a map mapping ds.getKey() to the value of worker_id when onDataChange is first called, and then comparing the value you get against that for any updates.

Related

Firebase Realtime database read not working (Android Java)

I am using realtime database in order to transfer information from a Windows computer to an Android phone. I am able to write data from the Windows PC to the database, but for some reason I am not able to read it off of the database to the Android. I am using Android studio Java. Here is the code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userRef = rootRef.child("users");
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String name = ds.getKey();
PCs.add(new PC(name));
}
for (int i = 0; i < PCs.size(); i++) {
PCs.get(i).setIp(dataSnapshot.child(PCs.get(i).getName()).child("ip").getValue(String.class));
PCs.get(i).setConnected(dataSnapshot.child(PCs.get(i).getName()).child("status").getValue(Boolean.class));
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
It just doesn't go into the onDataChange method, but also doesn't go to the onCancelled method.
If it goes into neither of the callbacks, you may not have configured the connection to the database correctly. An easy way to fix that is to pass the database URL in the code, rather than depending on the google-services.json file:
DatabaseReference rootRef = FirebaseDatabase.getInstance("your database URL").getReference();
In general, you should never ignore possible errors, and implement onCancelled. At its minimum that should look like:
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}

Android Firebase Database keeps updating value and eventually app crash

Whenever I updated the value 1st time, it works fine. But whenever I updated it again within a minute. The problem started, Firebase keeps updating, and as a result the apps crash. Can anyone help?
private void UpdatedStatus(String roomkey,String rents_not){
reference= FirebaseDatabase.getInstance().getReference("Room");
Query query = reference.orderByChild("Roomkey").equalTo(roomkey);
if (reference != null) {
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot dataSnapshot1 : snapshot.getChildren())
{
String childPath=dataSnapshot1.getKey();
referenceUpdated = FirebaseDatabase
.getInstance().getReference("Room").child(childPath);
HashMap<String, Object> map = new HashMap<>();
map.put("Status", ""+rents_not);
referenceUpdated.updateChildren(map).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(getApplicationContext(), "Updated", Toast.LENGTH_SHORT).show();
finish();
dialog.dismiss();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
In your current code, you do the following:
Set up a query for rooms with "Roomkey" == roomkey.
Attach a listener for updates on rooms that match the query
Upon getting results, set each matching room's status to rents_not
When you call UpdatedStatus("room1", "AVAILABLE"), everything works "fine" (the room "room1" is changed to AVAILABLE, then the room is changed to AVAILABLE again and finish.). Because you used addValueEventListener to listen for updates to the matching rooms, your code gets rerun when the data changes. This is why I said the status is changed twice.
Next, when you call UpdatedStatus("room1", "RENTED"), you experience the crash. After calling UpdatedStatus the second time, the status is changed to "RENTED", which fires both of the listeners from UpdatedStatus("room1", "AVAILABLE") and UpdatedStatus("room1", "RENTED"), constantly switching between "RENTED" and "AVAILABLE" forever.
You can fix this loop (and the double write) by using addSingleValueEventListener() instead. This will execute and read from the query only once.
FirebaseDatabase mDatabase = FirebaseDatabase.getInstance();
DatabaseReference mRoomsRef = mDatabase.getReference("Room");
private void UpdatedStatus(String roomkey,String rents_not){
Query roomQuery = mRoomsRef.orderByChild("Roomkey").equalTo(roomkey);
roomQuery.addSingleValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot childSnapshot: snapshot.getChildren())
{
String childPath = childSnapshot.getKey();
DatabaseReference childRef = childSnapshot.getReference();
HashMap<String, Object> map = new HashMap<>();
map.put("Status", ""+rents_not);
childRef.updateChildren(map)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(getApplicationContext(), "Updated", Toast.LENGTH_SHORT).show();
finish();
dialog.dismiss();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.e(TAG, "Failed to get rooms for key: " + roomkey + "; " + error.getMessage());
}
});
}
}
As auspicious99 answered, since you update the same node that your query is listening for, your own call to updateChildren ends up triggering onDataChange again. And since you then update the node again, it triggers again, and again, and again... etc.
There are a few solutions for this:
Use addListenerForSingleValueEvent, which triggers only once and stops listener after that. This is the simplest change, as you can just change
query.addValueEventListener(new ValueEventListener() {
to
query.addListenerForSingleValueEvent(new ValueEventListener() {
You can also choose to detect whether the Status field is already set to rents_not and skip the update if it is. Inside the loop in onDataChange, you can do this with:
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot houseSnapshot: snapshot.getChildren()) {
DataSnapshot statusSnapshot = houseSnapshot.child("Status");
String status = statusSnapshot.getValue(String.class);
if (!rents_not.equals(status)) {
statusSnapshot.getReference().setValue(rents_not).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Toast.makeText(getApplicationContext(), "Updated", Toast.LENGTH_SHORT).show();
finish();
dialog.dismiss();
}
});
}
}
You'll note that I've updated the code here a bit, since you can get the reference from the snapshot, and perform the update at the lower level.
These will both fix your current problem, so pick whichever works for the use-case. But since your new value of the Status node depends on its current value, consider using a transaction to update it, to eliminate the risk that two users will both post conflicting updates.
It looks like you may have an unintended loop, as inside your onDataChange, you are doing referenceUpdated.updateChildren(map), which changes data in your firebase database. This triggers onDataChange again, and so on.
You could break the circle by setting a Boolean/flag and checking it as needed.

Retrieve data from FireBase database in android, java by searchin with an ID

I tried to implement a code in java to retrieve data from database( firebase) by searching with an ID and show it in the form.
In here i have already saved some data and now when i type the id, it need to show the data of the id in this same form.
btnShow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
searchID = txtid.getText().toString().trim();
DatabaseReference readRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference dref = readRef.child("Student");
Query query = dref.orderByChild("id").equalTo(searchID);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChildren()){
txtID.setText((dataSnapshot.child("id").getValue().toString()));
txtName.setText((dataSnapshot.child("name").getValue().toString()));
txtAdd.setText((dataSnapshot.child("address").getValue().toString()));
txtConNo.setText((dataSnapshot.child("conNo").getValue().toString()));
}
else
Toast.makeText(getApplicationContext(),"No Source to Display",Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
This is the java code i implemented to do that. But when i run the program and give the correct id in database it is always showing as "No source to display"( There are data in my database and save function is working properly)
I am a beginner in android studio and firebase. Please modify the above code and tell me how can i search by ID.
Thankyou.
Try the following:
if(dataSnapshot.exists()){
for(DataSnapshot ds : dataSnapshot.getChildren()){
txtID.setText((ds.child("id").getValue().toString()));
txtName.setText((ds.child("name").getValue().toString()));
txtAdd.setText((ds.child("address").getValue().toString()));
txtConNo.setText((ds.child("conNo").getValue().toString()));
}
}
Your reference is at node Student therefore you need to loop and then use ds to access the attributes. Also, don't forget to check for errors inside onCancelled:
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore potential errors!
}

How Can I get The Child Id Of the Root Node In Firebase Realtime Database?

This is my RealTime Database JSON data. I want to fetch the child id of the root node Assets. but can't seem to figure out as I am not using userid instead I am scanning a barcode and saving the data under the particular barcode number.
Here's the Screenshot
To get those keys, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference assetsRef = rootRef.child("Assets");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String key = ds.getKey();
Log.d(TAG, key);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
assetsRef.addListenerForSingleValueEvent(valueEventListener);
The result in the logcat will be:
CFM100010254BG
GE123100010254GB
If you want only the first child (CFM100010254BG), instead of using a DatabaseReference, please use the following query:
Query query = assetsRef.orderByChuild("asset_model").equalTo("CFM56");
And attach the listener on this query.

How to retrieve data child of child from firebase / Android

Here is my firebase database
Here is the info.class
Here is the insert
I want to get all the data from firebase to List View
How can i get all data under "information" data list ?
please help
db = FirebaseDatabase.getInstance();
ref = db.getReference("infomation");
protected void onStart() {
super.onStart();
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
infoList.clear();
for (DataSnapshot infoSnapshot : dataSnapshot.getChildren()){
info info = infoSnapshot.getValue(info.class);
infoList.add(info);
}
InfoList adapter = new InfoList(Welcome.this, infoList);
listViewInfo.setAdapter(adapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
In your insertion part, you need to change it like below,
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("information");
ref.child( FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(in);
but if you want to save data like save the data like
information >uid> random value > then the data
that use change data retrieving part like below
for (DataSnapshot infoSnapshot : dataSnapshot.getChildren().getChildren()){
info info = infoSnapshot.getValue(info.class);
infoList.add(info);
}

Categories