I've just started with firebase in android and i can't understand some things in onStart and in onStop.
Why is it necessary to have this code on stop method? Why do we need to remove listener ?
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
if(mAuthStateListener != null)
mAuth.removeAuthStateListener(mAuthStateListener);
}
And one more question what is the advantage of setting up mAuth listener in onStart method instead of onCreate ?
#Override
protected void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
mAuth.addAuthStateListener(mAuthStateListener);
}
This is how they shoved in Firebase -> Authentication demo.
There is the need to remove listeners because the mAuth will keep of keeping track of all the listeners you added, in order to notify you when something happens.
When the activity stops you remove the listener from the list because well, the activity has stopped anyway, there is no need to listen for auth events when the activity is stopped, is there?
Why add the listener at onStart then?
Because according to the activity life cycle:
onStart and onStop correspond to each other, while onCreate and onDestroy correspond to each other.
If you add the listener in onCreate and remove at onStop, the listener will not be added back when the activity restarts, since onCreate is not called on restart. onStart is.
Related
We have put the Firebase auth listener in a specific activity in the Android app. It only works when that activity occurs.
auth.addAuthStateListener(new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() == null) {
Log.i("firebase", "AuthState changed to null");
}
else {
Log.i("firebase", "AuthState changed to "+firebaseAuth.getCurrentUser().getUid());
}
}
});
From what I understood, the firebase auth listener listens all the time and is triggered as soon as the firebase auth state changes. However, this does not seem to be the case in our case. Do we have to put this code in every activity or is there any way to put this in a single place and it lets us know as soon as the firebase authentication status changes?
You can get that code out of the activity and put it into a separate (repository) class. You can save the auth state into a LiveData object that can be observed in all your activities. According to the result, you can take some actions in your activity.
If you understand Kotlin, I have created an app for learning purposes where I have implemented this mechanism:
https://github.com/alexmamo/FireApp
Another solution would be to have a single activity with several fragments. In this case, you need to attach the listener only once in the activity.
I try to call a method that calls getSupportFragmentManager() however i get:
IllegalStateException: FragmentManager has not been attached to a host.
The broadcast receiver fires and the method which is in the activity which is currently in the UI fires as below but i get the error:
BottomSheet bottomSheet = new BottomSheet();
bottomSheet.show(getSupportFragmentManager(), "bottomButtons");
All i am attempting to do is call the bottomSheet from a service which i have to do via a broadcast receiver as i cant call getSupportFragmentManager from the service! How can i get the sheet to appear, triggered by an event in my service?
Fragments are part of the UI. BroadcastReceiver and Service are background components and do not have anything to do with UI. You cannot even call the method getSupportFragmentManager() from a BroadcastReceiver. This shouldn't even compile!
Only Activity components can do stuff with the UI.
To Call the method which displays my BottomSheet which is situated in the Activity that is currently displayed in the UI from a background service. I used MutableLiveData.
I initialised a global Boolean finished, in my service;
public static MutableLiveData<Boolean> finished = new MutableLiveData<Boolean>();
When the required event triggers in my Service i set the value of the live data variable to true. with
finished.setValue(true);
In the activity i need to display the BottomSheet i am observing this variable via:
finished.observe(this, new Observer<Boolean>(){
#Override
public void onChanged(Boolean aBoolean){
if(aBoolean){
//I call my Method here which displays my Bottom Sheet, this is the method that contains the getSupportFragmentManager().
}
}
});
I hope this can help anyone in my situation.
When restarting an Activity, onStop() from previous activity delays too much to be called.
I am using this code to restart my activity PlayerActivity.java
Intent playerIntent = getIntent();
playerIntent.putExtra(Constants.VIDEO_ID, videoId);
playerIntent.putExtra(Constants.CATEGORY_ID, categoryId);
playerIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(playerIntent);
Let's call PreviousPlayerActivity and NewPlayerActivity, the activity that was before and the new activity. (remembering that they are the same PlayerActivity).
Sequence
When restarting the app follows this flow in the activity-lifecycle.
PreviousPlayerActivity onPause() -->
NewPlayerActivity onCreate() -->
NewPlayerActivity onStart() -->
NewPlayerActivity onResume() -->
NewPlayerActivity performs a heavy operation -->
PreviousPlayerActivity onStop() -->
PreviousPlayerActivity onDestroy()
What I need
I need PreviousPlayerActivity to be completed destroyed before NewPlayerActivity starts. However, onStop() is just called after the heavy operation, so it delays around 10 seconds to be called.
What I tried
If I use recreate() method it does destroy PreviousPlayerActivity before calling NewPreviousActivity, but by calling recreate() I can not putExtras into the new activity instance.
Questions
How to completely destroy PreviousActivity when restarting an activity?
Is there a way to putExtras while using recreate()?
In Activity Lifecycle from Android Developer guide.
Coordinating activities
When one activity starts another, they both experience lifecycle
transitions. The first activity stops operating and enters the Paused
or Stopped state, while the other activity is created. In case these
activities share data saved to disc or elsewhere, it's important to
understand that the first activity is not completely stopped before
the second one is created. Rather, the process of starting the second
one overlaps with the process of stopping the first one.
The order of lifecycle callbacks is well defined, particularly when
the two activities are in the same process (app) and one is starting
the other. Here's the order of operations that occur when Activity A
starts Activity B:
Activity A's onPause() method executes.
Activity B's onCreate(), onStart(), and onResume() methods execute in sequence. (Activity B now has user focus.)
Then, if Activity A is no longer visible on screen, its onStop() method executes.
This predictable sequence of lifecycle callbacks allows you to manage
the transition of information from one activity to another.
So the behavior that you describe is expected or predictable.
Back to your questions.
1.How to completely destroy PreviousActivity when restarting an activity?
Using recreate API, the limitation is it only works from API 11 or above
2.Is there a way to putExtras while using recreate()?
From recreate documentation
recreate
public void recreate ()
Cause this Activity to be recreated with a new instance. This results
in essentially the same flow as when the Activity is created due to a
configuration change -- the current instance will go through its
lifecycle to onDestroy() and a new instance then created after it.
Because the activity will be recreated so onSaveInstanceState and onRestoreInstanceState will be called as well. As you can guess the idea is save data in onSaveInstanceState and retrieve in onRestoreInstanceState or onCreate.
Step 1: Save data in onSaveInstanceState
// The key for saving and retrieving isActivityRecreated field.
private static final String KEY_IS_ACTIVITY_RECREATED = "KEY_IS_ACTIVITY_RECREATED";
/** true if this activity is recreated. */
private boolean isActivityRecreated = false;
// Call this method when you want to recreate this activity.
private void recreateActivity() {
isActivityRecreated = true;
recreate();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_IS_ACTIVITY_RECREATED, isActivityRecreated);
outState.putInt(Constants.VIDEO_ID, videoId);
outState.putInt(Constants.CATEGORY_ID, categoryId);
}
Step 2: Retrieve the data in onRestoreInstanceState or onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
isActivityRecreated = savedInstanceState.getBoolean(KEY_IS_ACTIVITY_RECREATED);
if (isActivityRecreated) {
// This activity has been recreated.
// Reset the flag
isActivityRecreated = false;
// Write your code when this activity recreated.
int videoId = savedInstanceState.getInt(Constants.VIDEO_ID);
int categoryId = savedInstanceState.getInt(Constants.CATEGORY_ID);
...
}
}
}
You can do it simply by setting a noHistory flag as true in AndroidManifest.xml file. I think you don't need to keep that activity state when minimizing according to your requirement.
<activity
android:name=".PlayerActivity"
android:noHistory="true" />
I am trying to call onPause(), onStop(), onDestroy from a specific button to exit the application (this is my assignment details).
This is the code I've written:
Button exitBtn = (Button) findViewById(R.id.exitBtn);
exitBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Button Exit clicked
// going through the LifeCycle
MainActivity.super.onPause();
MainActivity.super.onStop();
MainActivity.super.onDestroy();
}
});
But when I click the button in the application it stops suddenly and displays the message: "App has stopped".
It shouldn't crash it should just exit the application
Call finish() on MainAcitivty instead of directly calling those methods. Or another bad way of doing it would be executing the following:
System.exit(0)
As someone mentioned in the comment above, onPause(), onStop(), and onDestroy() are called by Android system itself. Check this out for more understanding about Activity lifecycles.
I am creating an app. From MainActivity -> Fragment -> See Details Activity.
It is working fine.
But when I am going to background on See Details Activity, it is still running.
Why this activity or app is not getting destroyed. I want to kill the app whenever I will go to background.
Add this:
#Override public void onPause() { super.onPause(); // Always call the superclass method first
Finish();
}
Invoke finish() method before start Fragment