I want to retrieve data continuously from firebase realtime database. I have made a service for that purpose but, the service do not stops on calling stopService. I want to stop service when i got the appropriate data. Please help.
I tried
Intent intent = new Intent(MainActivity.this,BackgroundSoundService.class);
stopService(intent);
But this didn't not work. What else i need to do to stop this service?
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
IniTializeSpeech(getApplicationContext());
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("objectsData").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String ss =(String) dataSnapshot.getValue();
Log.i("OnDataChange",ss);
t1.speak(dataSnapshot.getValue().toString(), TextToSpeech.QUEUE_FLUSH, null);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
If you're only interested in getting the data once, you can instead use addListenerForSingleValueEvent:
mDatabase.child("objectsData").addListenerForSingleValueEvent(...
If you have a more complex condition, you can use your current code to register. But to later stop the event listener from responding to data changes, you need to remove that listener.
To do this, you first keep a reference to the listener when you register it:
ValueEventListener myListener = mDatabase.child("objectsData").addValueEventListener(...
And then you can later remove it with:
mDatabase.child("objectsData").removeEventListener(myListener)
Related
I am trying to add online/offline feature in my android chat app using .info/connected path
I wrote the following code inside onCreate() method
studentref = FirebaseDatabase.getInstance().getReference("student").child(user.getUid());
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) {
studentref.child("status").onDisconnect().setValue("offline");
studentref.child("status").setValue("Online");
} else {
studentref.child("status").setValue("offline");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
But the else part does not execute when i minimized the app for more than 60 seconds
It only works when i killed the app or when i switch off the internet for more than 60 seconds
How to make it works , when the app is in foreground it should set the value "online" and when the app is in background or killed it should set the value to "offline"
I solved this issue using 2 ways
First we need to detect when the app goes to the background and come back to the foreground , so when the app goes to foreground update the user state as "Online"
when the app goes to background update the user state as "Offline"
We can achieve this by implementing LifecycleObserver class and writing the following 2 methods
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
// here update user state as offline
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
// here update user state as online
}
But this will not work when there is no internet connection , Eg: when the user switch off the internet while the app in foreground and close the app in this case the user state will remain online even the app is closed , To solve this we need also to check the connection to .info/connected path
connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
listenerCon = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
user= FirebaseDatabase.getInstance().getReference("users").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
user.child("state").setValue("Online");
user.child("state").onDisconnect().setValue(ServerValue.TIMESTAMP);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
};
connectedRef.addValueEventListener(listenerCon);
So when there is no connection for more than 60 sc the user state will be updated to offline
The .info/connected reflects the connection of your application to the backend servers of the Firebase Realtime Database. While this may have some relation to whether the user is actively using the app, it is not a 1:1 mapping.
If you want to detect whether the app is backgrounded, there are better ways (unrelated to Firebase) such as How to detect when an Android app goes to the background and come back to the foreground and others from these search results.
Use my code, in onCreate
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String id = user.getUid();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child("Users").child(id).child("stateOnline");
if (user != null){
reference.setValue(true);
reference.onDisconnect().setValue(false);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
// CONNECTED
} else {
// NOT CONNECTED
}
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
});
reference.keepSynced(true);
}
My Firebase Realtime Database has been built by loading an object of the Java class HashMap. In my Android Studio app I'm trying to write a method that takes a String (the key) as input, searches through the database and if the string is found it returns the associated Float (the value), otherwise it returns 0. How can I do this? Any help would be really appreciated!
EDIT: I've tried to follow the suggestions, adapting them to my particular case, but I didn't manage to solve the problem yet.
I wrote the following code in MainActivity:
DatabaseReference myRef;
Float tempValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
myRef = FirebaseDatabase.getInstance().getReference("myRoot");
tempValue=0f;
...
}
public void retrieveValueFromDatabase(String childName, final MainActivity activity){
myRef.child(childName).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Float value=dataSnapshot.getValue(Float.class);
if (value==null){
value=0f;
}
activity.tempValue=value;
//First Toast
//Toast.makeText(activity,"tempValue = "+tempValue.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
public void useValues(){
retrieveValueFromDatabase(childName,this);
//Second Toast
//Toast.makeText(this,"tempValue = "+tempValue.toString(), Toast.LENGTH_LONG).show();
//code using tempValue from here
...
}
If I uncomment the first toast, the correct value inside tempValue is shown, but if I uncomment the second toast, the value of tempValue shown is the default one (0.0). What am I missing?
You need to use addValueEventListener to retrieve data from the database:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("myRoot").orderByChild("name").equalTo("peter");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("Database", dataSnapshot.child("floatValue").getValue(Long.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})
Here, you add a reference to the root node, then query using equalTo() to check if name = peter exists in the database and return the float value.
You should read the guide:
https://firebase.google.com/docs/database/android/read-and-write
I can get data from Firebird DataBase but they are updated only if I restart the activity how to do it without restarting the activity.
The code snippet with the implementation of retrieving data
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long coinsAmount = dataSnapshot.child("coinsAmount").getValue(Long.class);
text.setText(String.valueOf(coinsAmount));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
uidRef.addListenerForSingleValueEvent(valueEventListener);
Change
uidRef.addListenerForSingleValueEvent(valueEventListener);
to:
uidRef.addValueEventListener(valueEventListener);
This way, your listener will be called each time the value in the DB changes,
and not only once.
Read more about difference between valueEvent and singleValueEvent.
Is there any way to pull data from firebase where the code is? I currently have valueEventListeners, but they all run after the code below them, thus invalidating the following code. I want to be able to pull a value exactly where the code is, not later.
As of yet, I have not found anything online about this.
A good example of my problems in the code:
public void onItemClick(AdapterView<?> l, View v, final int position, long id) {
FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
final String uid = user.getUid();
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
cCESnapshot = dataSnapshot.child(uid).child("currChallenges").child(challengeList.get(position));
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Intent intent = new Intent();
intent.setClass(this, ChallengeView.class);
intent.putExtra("snapshot", cCESnapshot.toString());
intent.putExtra("name", challengeList.get(position));
startActivity(intent);
}
cCESnapshot is null because the intent runs before the valueEventListener.
The onDataChange() is asynchronous, so the only way to use the retrieved data is inside onDataChange(), example:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
cCESnapshot = dataSnapshot.child(uid).child("currChallenges").child(challengeList.get(position));
Intent intent = new Intent();
intent.setClass(this, ChallengeView.class);
intent.putExtra("snapshot", cCESnapshot.toString());
intent.putExtra("name", challengeList.get(position));
startActivity(intent);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
This is an asynchronous operation, when the data will arrive, the onDataChange callback will be triggered. Your startActivty code will be executed sequentially and this is why you get no value in cCESnapshot.
Move the startActivity code inside the listener.
But be careful, because each time the onItemClick click listener will be called, you'll add a value event listener. That way, you'll have multiple calls to onDataChange in each click and so multiple startActivities.
Instead, i recommend using addListenerForSingleValueEvent which will be triggered only after a single change in data.
mRefQ.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String txt = dataSnapshot.getValue(String.class);
showtext.setText(txt);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
as it stands i can only access the value when the data is changed but i want to access it whenever i want(namely oncreate).
From the Firebase documentation for listening to value events:
This method is triggered once when the listener is attached and again every time the data, including children, changes.
You can access the Data only once by following this steps.
As #Frank mentioned having a listener will give you access when attached and every time it changes.
Bear in mind that all of this happens asynchronously on a separate thread, therefore in order to ensure the value is available on onCreate you may have to do the orchestration yourself and hold the main thread until the values is ready to be used.
Alright so it turns out it does call it when created, i just had to wait for the firebase to load up on the app
It is not triggerred once in onCreate() method. Without removeEventListener, addValueEventListener will never stop if you listen it in OnCreate() Method. Count is increasing and never stops and load was up to 85% when I run it and so I had to close my internet and uninstall it. But ienter image description heret has just been solved. Here's my code if you wanna check it.
Variables are declared global...
private DatabaseReference main;
private ValueEventListener valueEventListener;
In onCreate() Method.....
valueEventListener = main.addValueEventListener(new
ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
boolean countExists = false;
int count = 1; //starts from 1 when data is uploaded for the first time
for (DataSnapshot out: dataSnapshot.getChildren()) {
if (out.getKey().equals("count")) {
String temp = out.getValue(String.class);
countExists = true;
try {
count = Integer.parseInt(temp);
}
catch (NumberFormatException e) {
count = 1;
}
break;
}
}
if (!countExists) {
main.child("count").setValue(String.valueOf(count));
Toast.makeText(getApplicationContext(), "Count Created", Toast.LENGTH_SHORT).show();
upload.setClickable(true);
}
else {
main.child("count").setValue(String.valueOf(++count));
Toast.makeText(getApplicationContext(), "Count Updated", Toast.LENGTH_SHORT).show();
upload.setClickable(true);
}
main.removeEventListener(valueEventListener);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "Failed to upload", Toast.LENGTH_SHORT).show();
}
});
Make sure you add removeEventListener when you call it in onCreate() method or it will never stops. It is not a problem if you don't call removeEventListener in onStart() method.
This is not your question but...
If you wanna use firebase for likely free, you can't let all users to download your data without necessary or your bandwidth may become full within a day. So, I count the data and just download that child's value and compare the result and make update. So it can reduce your bandwidth when you call addValueListener.