When my app is inactive for some time android kills its process, making all static variables null. destroying activities etc. I want my app to launch MainActivity(activity that is declared as launcher in manifest) instead of activity that was in foreground when my app got minimalized and later killed.
Thanks in advance
The right way to do this would be to store the data you need (that you are storing just on your static vars) on the database and use the memory just as cache.
The not so good hammer time way to do it... is simple. In each onCreate of the Activities that need that info, check if the info is null, and if it is, invoke finish() and startActivity with the one you want.
#override
protected void onCreate(){
super.onCreate();
...
if(Singleton.getInfo() == null){
this.finish();
startActivity(...)
}
}
Or u can go to MainActivity with intent`s if you need pass some information from that activity.
Yet another possibility : As described in Clearing the back stack you can add clearTaskOnLaunch="true" to the root activity :
If this attribute is set to "true" in the root activity of a task, the
stack is cleared down to the root activity whenever the user leaves
the task and returns to it. In other words, it's the opposite of
alwaysRetainTaskState. The user always returns to the task in its
initial state, even after a leaving the task for only a moment.
Related
This is a huge Android Programming issue/bug.
Calling finishAffinity() does not shut down my application.
This is evidenced from the fact that:
1. The Android Studio Debugger still says 'Application is running' even after the app disappears from the screen and I'm back to the phones home screen.
2. When 'restarting' the application the values of data members of the inital Activity remain the same as they were before the application supposedly 'shutdown'.
3. If I call System.exit(0) directly after finishAffinity() then the shutdown works properly and data members are reset to their initial default values.
There are even bigger implications to this problem! When I call finish() within ActivityA after starting another ActivityB, if I ever go back to ActivityA then the data members have not been reset to default are still the old values.
This is ALL confusing to me since I've come from C++ where when a class is destroyed then it is ACTUALLY destroyed and all memory associated with it is completely released.
Getting an activity to completely delete itself when switching to a new activity or trying to exit the application seems IMPOSSIBLE.
public class Startup extends AppCompatActivity
{
private static int iStarted = 0;
............
#Override
protected void onActivityResult(int request, int result, Intent data)
{
super.onActivityResult(request, result, data);
if (request == RESULT_EULA_RETURNED)
{
// shutdown
finishAffinity(); // iStarted remains = 1
return;
}
}
..........
#Override
protected void onResume()
{
super.onResume();
// perform startup
// even when restarted this remains = 1
if (iStarted == 0)
{
iStarted = 1; // this will stay = 1 until the application is manually killed via the CLOSE ALL method or via the debugger
}
}
}
finishAffinity() is not used to "shutdown an application". It is used to remove a number of Activitys belonging to a specific application from the current task (which may contain Activitys belonging to multiple applications).
Even if you finish all of the Activitys in your application, the OS process hosting your app does not automatically go away (as it does when you call System.exit()). Android will eventually kill your process when it gets around to it. You have no control over this (and that is intentional).
If you have a debugger attached to the process, this can also prevent the process being killed by Android, as the debugger keeps active objects in the process.
You talk about "data members" not being cleaned up, and you claim that this works differently in C++. Actually, that's not true. Your "data members" are declared static. They aren't instance variables, they are class variables. They exist only once (not in every instance of the class), they are created and initialized when the class is loaded, and they are never destroyed until the class is unloaded (which never happens on Android). C++ has exactly the same behaviour.
You might try using instance variables instead of class variables to solve your problem.
Android has no concept of "shut down my application". There is only the Android Activity life cycle. There is not a connection between the VM's object life cycle on the activity life cycle; Android is free to re-use your Activity object instance across on create / destroy boundaries. In short, you can't assume Android will ever construct a new Activity object to handle a life cycle event.
You'll need to manage your own state. For example, maybe you want to clear them in onCreate() so whenever you activity is re-created they are reset. Note that I don't presume to know what logic you want to apply to the problem, I'm just giving an example.
Since I store certain information that is necessary in my Application class, when a user encounters a crash, sometimes they encounter two crashes since the last activity needs information stored in the application class.
Activity A >> Activity B (needs info from Application class) >> Activity C
Crash occurs on C >> Application tries to open Activity B >> Crash occurs on B because it needs info from the Application class (this has been reset)
I want to avoid this, so I was hoping that there is someway I can restart the whole application after a crash instead of the activity.
This is one possible solution of many but I'll put it here as an option:
You could use startActivityForResult() and when you handle the error in Activity C, finish() it with a result code that you recognize as a crash and handle things appropriately in the onActivityResult() of Activity B.
Getting a Result from an Activity
The nicest solution is to handle the case in which you do not have the necessary information at any activity (in your case Activity B).
You should check at the onCreate method whether you have the information or not, and act in consecuence:
Finishing the activity to go back to your activity A
Launching another activity
Asking the user for feedback
Any other action you think fits best
There may be more than one reason explaining why you don't have that information (as other answers point out), so in my opinion the best option is to handle the case.
Untested theory, just spitballing.
Could you attach yourself as a default exception handler, and start calling finish() on the open activities? If you can finish all your activities, wouldn't that effectively shut down the app, and reopening it would be as if it were getting launched fresh?
You shouldn't keep any state in the Application object. Keep it in the Bundle you receive in the onCreate(). Eventually use onSaveInstanceState / onRestoreInstanceState to save/restore state.
Because an app I'm building will handle rather sensitive data I want to sync the SQLite db with the server every time the user logs in, and remove emty the db every time the app loses focus (because the user moves to the home screen or another app).
Seeing the Activity lifecycle, my idea was to do this by emptying the database in the onDestroy of every Activity. To test the described lifecycle I just Override all lifecycle methods (onCreate, onStart, onResume, onPause, onStop, and onDestroy), included some log messages in them, and fired up my app.
The log messages are included in my SettingsActivity. When I enter my app and move to the Settings it runs onCreate, onStart and onResume (as expected). When I then click a setting and move to the next screen it runs onPause and onStop (still as expected). To move back to the settings screen I click the back button and it runs onStart and onResume again (still as expected), when I now click the back button again to move back to the initial screen, it (to my surprise) runs onPause, onStop AND onDestroy.
So my questions;
Why does it destroy the Activity when the app is not finished?
And more importantly: how can I run my CleanUp method when the app closes or loses focus?
You can have some more information here : http://developer.android.com/training/basics/activity-lifecycle/stopping.html
Even if I think you already read it because you already study the activity lifecycle, you can see in the first figure that the onDestroy() is called after the onStop() and this call is totally managed by the system : you shouldn't expect any behavior. The system will decide itself WHEN to call this method, and sometimes, this method will never be called (see here : http://developer.android.com/reference/android/app/Activity.html). When system needs memory, your activity will pass in onStop() and nothing more.
So, to answer your second question, you shloud read the note in the documentation about the onDestroy() method :
Note: do not count on this method being called as a place for saving
data! For example, if an activity is editing data in a content
provider, those edits should be committed in either onPause() or
onSaveInstanceState(Bundle), not here. This method is usually
implemented to free resources like threads that are associated with an
activity, so that a destroyed activity does not leave such things
around while the rest of its application is still running. 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.
So it's pretty clear that it's a bad place to make your clean-up process. So you shloud use one of onPause() or onStop() method.
onStop() is described like this in the documentation :
Called when you are no longer visible to the user. You will next receive either onRestart(), onDestroy(), or nothing, depending on later user activity.
onPause() is described like this in the documentation :
Called as part of the activity lifecycle when an activity is going
into the background, but has not (yet) been killed.
[...]
When activity B is launched in front of activity A, this callback will be
invoked on A. B will not be created until A's onPause() returns, so be
sure to not do anything lengthy here.
[...]
In situations where the system needs more memory it may kill paused processes to reclaim resources.
We now know that onPause() is designed to allow you to save your data, and also that after onPause() was executed, the system could kill your process. So, making the clean-up in onPause() seems to be the safest place as you're pretty sure it will be called everytime.
Also, as you can read, making your clean up here can make your app slow, but anyway cleaning and recreating your database at each gain/loose of focus is a really heavy process...
To resume : make your clean up process in the onPause() method and your init process in the onResume(). Keep it mind that your application can be really slow with this kind of process.
Hope this can help you.
Destroying the Activity on back is the normal behavior. From the Android developers site
There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button...
Has for detecting when the application goes to background, there is no simple method call that will let you know that. However this previous question contains some nice answers on how to do it.
You can't do this (call a function) in java part of app.
Only in the native part.
About your second question, this way you could run your CleanUp method when the app closes fully. You will need to implement your method inside a service that in this case I named "ExitService"
First create this service class:
public class ExitService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
System.out.println("onTaskRemoved called");
super.onTaskRemoved(rootIntent);
//do something you want before app closes.
ADD YOUR METHOD HERE, or CALL IT
//stop service
this.stopSelf();
}
}
Then, declare this way your service in the manifest "application" label:
<service
android:enabled="true"
android:name=".ExitService"
android:exported="false"
android:stopWithTask="false" />
Now, just start the service wherever you want to do something before your app closing.
Intent intent = new Intent(this, ExitService.class);
startService(intent);
Is there some sort of onTerminate() method where I can do some cleanup (I want to clear some SharedPreferences) when my Android app is terminating?
I have an Activity that is keeping a running average of a few numbers, that I'm storing in a SharedPreference. I want this average to last while the app is running (the user can move between different activities) so I can't clear it on onDestroy() for that particular activity. I need to be able to clear it once the app is about to quit.
How can I do this?
I've not tried this, but here's what I would do:
As Alex mentioned in the comment to original question, use a Service to share the app-wide state between Activities.
Whenever you move between Activities, bind to the service from the "new" activity, and unbind from the "old" one. Check this to understand how to coordinate activities.
If you follow this properly, you can ensure that at least one Activity is always bound to the Service as long as your app is running; and that all Activities are unbound when the app is no longer running - at which point your service's onDestroy() is called. This is where you perform your cleanup.
So android doesn't really have a concept of an app being "finished". Unfortunently there is nothing synonymous to "onTerminate()". Is there some criteria by which you can decide when to clear your running average?
Use SharedPreference.Editor to remove the preferences, and commit. Here's a link for you: http://developer.android.com/reference/android/content/SharedPreferences.Editor.html
I need to count the number of times the user launches an app. I'm storing the value in a shared preference, and putting the count logic inside onCreate().
Now, since onCreate() is called in a number of different scenarios, not all of which include the user actually launching the application, I'm using the saved instance state bundle to store a flag set in OnSaveInstanceState() -- if the flag is absent, I consider the user started the app manually.
Is this necessary, or is just checking for a null bundle passed to onCreate() enough? In either case, why?
You could call getCategories() on the intent to see if it includes the LAUNCHER catagory.
You could think about this another way... increment the counter every time onDestroy() is called. This way you would be guaranteed that the program is actually out of memory, and the counter will only ever be off by 1 at most.
Just throwing an idea out there, hope it gives you some more of your own!
A null check in onCreate() should work just fine. No need to set a separate flag in onSaveInstanceState(). There is one possible issue though.
Say the user put your application in background (by pressing home key). The application process will eventually get killed. When the user restarts the application, you will receive a proper Bundle object in onCreate() with the flag set. The user can prevent your counter from being incremented by simply backgrounding your application everytime.
If backgrounding could be an issue, you might try something like:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (getLastNonConfigurationInstance() == null) {
counter++;
}
}
public Object onRetainNonConfigurationInstance() {
return new Object();
}
I have used the above code before and it works on Eclair, FroYo and Gingerbread. It seems getLastNonConfigurationInstance() and onRetainNonConfigurationInstance() have been marked deprecated in Honeycomb, so I am not sure how it will work in case you are targeting Honeycomb.
Inside the onCreate method, include a check to Activity#getCallingActivity. It returns null if the app was not started from another activity.
First off, thank you all for your answers. They all helped some way or another.
That said, after several tries and different approaches, I think there is no actual 100% reliable way of determining when the user has launched the app. None of the activity life-cycle callbacks can really be used tackle the issue, neither individually nor combined.
The closest I got was counting the number of onResume() calls, and then substracting from it in onPause() depending on the return of isFinishing(). This approach, however, doesn't account for the home button, among maybe other things a user can do to hide apps.
I will update this answer if I ever find a way to do this reliably.