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.
Related
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 have a simple application in which before I do anything, I must check whether the user is logged in or not.
To do this, I inherited the Application class like this:
public class GBApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
if (userIsLoggedIn()) {
Intent overviewActivity = new Intent(this, Overview.class);
overviewActivity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(overviewActivity);
}
}
}
userIsLoggedIn() returns a boolean stored in the SharedPreferences file.
Everything works, but when I press back from the Overview activity, it redirects me to the default activity (MainActivity), and removing it from the AndroidManifest.xml files gives error.
Also, I can't call finish() since this is a non activity class.
How can I terminate my program after I return from the Overview class? I found solutions where they pass a value to the MainActivity, call finish() from there. But this seems to complicated.
What else I can do?
This is my application tag in AndroidManifest.xml
Your plan is going to cause problems. Every time your process is created, you are starting an activity, even if an activity is not needed for this particular process.
Displaying a launcher activity — such as in response to the user tapping on a home screen launcher icon — is one way that a process might be created for your app. But there are many others:
AlarmManager
JobScheduler
a Notification
a push message (e.g., from Firebase Cloud Messaging)
a request sent to a ContentProvider that you export from your app
a request sent to a Service that you export from your app
a manifest-registered BroadcastReceiver
the user returning to your task in the overview screen
and so on
In none of those scenarios is displaying this activity necessarily appropriate. Yet, your code will display the activity in all of them, because any time Android forks a process for your app, you display this activity.
Have all of your activities (other than the login one) see if the user is logged in, and route the user to the login activity if that is needed. When the user completes the login, and the login activity finishes, the user is returned to where they were trying to go, whether that is your launcher activity or some other activity (e.g., they returned to your task after your app had been in the background for a while, so your process was terminated, but Android tries to send them back to whatever activity of yours they had been in last).
You could simply override the onBackPressed() of your overviewActivity and pilot the direction your app goes when the back button is pressed (which in your case is to shut down the app):
#Override
public void onBackPressed(){
startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
The code above just shuts down your app immediately the back button is clicked once (which is pretty boring.. but simple). You could also try the code snippet below; it pops up a dialogue box:
#Override
public void onBackPressed(){
new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int id){
startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
}
})
.setNegativeButton("No", null)
.show();
}
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.
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
i want to make a notification like BBM connected notification (for android)...
so when i open my app, the notification will appear, and it cant be canceled...
so i use this code
nm=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification=new Notification(android.R.drawable.stat_notify_more, "this is important", System.currentTimeMillis());
notification.flags = notification.FLAG_NO_CLEAR; //notification never dissapear
Context context=MainActivity.this;
CharSequence title="hello there";
CharSequence detail="this is demo";
Intent intent=new Intent(context,MainActivity.class);
PendingIntent pending=PendingIntent.getActivity(context, 0, intent, 0);
notification.setLatestEventInfo(context, title, detail, pending);
nm.notify(0, notification);
i put that code in public void onCreate(Bundle savedInstanceState)...
so, the notification cant cancel when i click or slide.
and when i close my app, the notification still there.
then i have an idea to use this code :
#Override
protected void onDestroy() {
nm.cancelAll();
}
but, this function never called???
how can i cancel the notification when i close the app?
It might be because onDestroy will not be called immediately when you navigate away with the home button.
Android has callback methods available that work well with notifications etc.
These are called onUserLeaveHint() and onUserInteraction().
The JavaDoc for onUserLeaveHint() states:
Called as part of the activity lifecycle when an activity is about to
go into the background as the result of user choice. For example, when
the user presses the Home key, onUserLeaveHint() will be called, but
when an incoming phone call causes the in-call Activity to be
automatically brought to the foreground, onUserLeaveHint() will not be
called on the activity being interrupted. In cases when it is invoked,
this method is called right before the activity's onPause() callback.
This callback and onUserInteraction() are intended to help activities
manage status bar notifications intelligently; specifically, for
helping activities determine the proper time to cancel a notfication.
I'd suppose you will want to override either one of these; especially onUserLeaveHint() seems a good choice for your purpose.
#Override
protected void onUserLeaveHint()
{
nm.cancelAll();
super.onUserLeaveHint();
}
You can't intercept the event of 'force closing' the application process. Android doesn't support this. When the user does this, the system calls Process.killProcess(int pid) and all resources will be freed. It's just not possible to catch this event and perform tasks before the process is really killed. Maybe a workaround is possible, but it wouldn't be how Android wants it.
There is no guarantee that the method will called. If application will not have enough memory, it can be killed by OS.
There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
You missed the super.onDestroy
#Override
protected void onDestroy() {
nm.cancelAll();
super.onDestroy();
}