App closing event in Android - android

Is there any way to know your application is running ?
I want to run a piece of code when Android app is just closed. Any suggestion will be appreciated.

Just to answer my own question now after so much time. When user close the app, the process is terminated with no notice. onDestroy is not guaranteed to be called. only when you explicitly call finish().

I suggest you to make a custom application class and note store the visibility of application wether it is running in background or not.obviously if you don't close the application like this
How to close Android application?
have a look at this so that you don't close it from background and perform the visibility check like this.
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
and this is how you register you application class to the manifest file.
<application
android:name="your.app.package.MyApplication"
android:icon="#drawable/icon"
android:label="#string/app_name" >
and override these two methods like this.
#Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
now check this status and perform what you like if it is running in background.You can take help of Booleans to check if the application is not closed by other reasons.

In general, there's no such thing as closing applications in Android: the user just stops using the app. It's up to the programmer to make sure that the user does not mention process creation and termination.
Please note that Android may kill the application process when it lacks memory and restart the application later.
For example, one of old office-like apps had the following bug: the user wanted to insert a photo, the office application invoked the Camera app, and Android killed the office app. The office app was not ready for a restart and lost all document changes (which was the bug). Apparently, the buggy app ignored the bundle passed to onCreate().
So the process life cycle and the application life cycle are different things. The process restart is visible to the application: the static variables get reset to their initial values (most likely, null). So it is possible to have a non-null bundle and null static data structures.
One example of executing a piece of code when the process dies may be found below:
Android camera locked after force close .
The problem solved in that post was that Android by itself does not close the camera when the process dies. I cannot tell from your post whether or not your problem is similar to this one.

If you uses, in your Activity, an object derivated from the class: ViewModel, you can capture the event: onCleared(); which is called always, after onDestroy().
See: https://developer.android.com/topic/libraries/architecture/viewmodel

Related

Which LifeCycleEvents to use in .NET MAUI on Android?

I have a View (with ViewModel, both Singleton) that reads and writes to a text file.
I would like it to be opened and closed in a controlled manner and am trying to work out where this should happen in the Maui app lifecycle.
In normal operation I assume that I should open it in OnAppearing and close in OnDisappearing.
If however the app is moved into the background and killed, OnDisappearing for the View does not fire.
It does fire OnPause, so I could close the file here and reopen it OnResume but would rather not use these for simplicity (although I will if recommended).
My questions are:
Is there any event that fires when the app is killed by the user (i.e. put in background and swiped away).
If the app is killed, will my text file be tidily flushed and closed?
Does anyone have any recommendations for better ways to do this. I am new to MAUI and may be missing something fundamental.
" Is there any event that fires when the app is killed by the user?"
No. Your app code does not get a chance to run at that time.
As you've discovered, there is a bit of a disconnect between App lifecycle (e.g Deactivated or OnPaused) and Page lifecycle (Appearing/Disappearing).
This is fundamental to Android itself, whether usng Maui or not. On Android, the only event that is guaranteed to happen before an app disappears is OnPaused; Maui app's Deactivated event runs when Android activity's OnPaused is called.
Unfortunately after OnPaused, its possible that your app will not get to run any other code later. You'll have to design everythng with that in mind.
Regardless of what page or popup your app is showing, or what it is in the middle of, your "app Deactivated" code is responsible for saving whatever information needs to be persisted.
Below follows one conceptual way to handle the situation.
"If the app is killed, will my text file be tidily flushed and closed?"
No. Unfortunately, there is no standard mechanism that does this for you.
The burden is on you to keep track of what "clean-up" is needed, depending on what user has done / is doing in app.
Consider defining public class BasePage : ContentPage class, that has some methods that manage this. Have your pages inherit from BasePage.
An example:
// In App.xaml.cs:
protected override void OnDeactivated()
{
CurrentPage?.SaveData();
...
}
private static BasePage CurrentPage;
public static void PageAppearing(BasePage page)
{
CurrentPage = page;
}
public static void PageDisappearing(BasePage page)
{
// Null CurrentPage, but skip that if has already changed to a different page.
// (Fixes a bug on some XForms implementations; haven't tested whether this is still an issue in Maui.)
if (ReferenceEquals(CurrentPage, page)
CurrentPage = null;
}
public class BasePage : ContentPage
{
// NO "InitializeContext". No XAML. Each subclass does that.
public BasePage(){ }
protected override void OnAppearing()
{
base.OnAppearing();
App.PageAppearing(this);
}
protected override void OnDisappearing()
{
App.PageDisappearing(this);
base.OnDisappearing();
}
public virtual void SaveData() {}
}
public partial class MyTextEditPage : BasePage
{
public override void SaveData()
{
... code to save text file being edited ...
}
}
The first thing I do in Deactivated/OnPaused is set a flag: DidPause = true; (refers to declaration private static bool DidPause;). I check that flag in Activated/OnResume, to know that app is continuing after going into background (but was not killed).
Next, have some mechanism to save data that "may have changed" (aka "dirty flag" is set on them), but have not been saved to local files. Save them. (If there is changed information that has not yet been successfully sent to a server, that is more complex. I save locally first; what to do after that is beyond scope of this answer.)
Third, pause or shutdown anything that doesn't need to run while app is in background.
In OnResume, if (DidPause) { DidPause = false; ... } code to restore anything that got shutdown or paused.
In this case, whatever page was showing should still be showing. Data saving was just a precaution, in case the app never comes back.
else { ... } (DidPause not set): The app is starting for first time, or after being killed.

Android Service execute AsyncTask after app closure

I am currently developing an Application for Android. One of the requirements is extensive logging about how the application is used. More specifically there should be logging about when the user closes the app. This logging consists of a server interaction. With respect to that specific requirement I stumbled onto:
Detect Application Exit(1) and Detect application Exit (2)
Both questions have an accepted answer relying on Service#onTaskRemoved(Intent).
In my case however this solution does not seem to work, i.e. AsyncTasks that are started in this method are only occasionally executed. More specifically, the onPreExecute is executed always but the doInBackground is not. I tested this on a Nexus 5 with Android 6 (Marshmallow) installed.
public class SomeService extends Service {
#Override
public IBinder onBind( Intent aIntent ) {
return null;
}
#Override
public void onTaskRemoved(Intent aRootIntent ) {
new DoSomethingTask().executeOnExecutor( Asyntask.THREAD_POOL_EXECUTOR );
}
private static final class DoSomethingTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
Log.e( DoSomethingTask.class.getName(), "This is executed always");
}
#Override
protected Void doInBackground( Void... aParams ) {
Log.e( DoSomethingTask.class.getName(), "This appears to be executed only sometimes... ");
// here an actual call to a Rest API should be made to inform the server that the user has closed the application.
}
#Override
protected void onCancelled( Void result ) {
super.onCancelled( result );
Log.e( DoSomethingTask.class.getName(), "Never invoked" );
}
#Override
protected void onCancelled() {
super.onCancelled();
Log.e( DoSomethingTask.class.getName(), "Never invoked" );
}
}
}
Here is an overview of everything I tried in addition to the above code sample:
I have tried various onStartCommand options (START_STICKY, START_NOT_STICKY, etc.) without success.
I have also tried restarting the service in the onTaskRemoved method and then executing the AsyncTask in the onStartCommand.
Starting an IntentService in the onTaskRemoved method (which starts the AsyncTask in its onHandleIntent method) solves the problem neither.
using a BroadcastReceiver in combination with a local broadcast (LocalBroadcastManager#sendBroadcast) does also not work (I double checked that the broadcast receiver is effectively registered as receiver for the sent broadcast).
EDIT:
I have also taken a look at the callbacks in the Application class:
- onTerminate : this method is only invoked in emulated environments and hence useless
- onTrimMemory(int) : this method can be used for detecting when the app goes to the background, but it has no distinct case for when the app exits.
I could keep an activity stack (which would be updated in Activity#onPause(), etc.). But this requires quite a lot of work in every single Activity instead of the above Service approach which only involves interference at a single place.
First of all: in Android you cannot guarantee execution for your requirement. Period. The system is free to gc your classes or kill your process at any time. Also the Android concept does not really have the concept of "closing app" actions the same way websites don't have it. So before you continue reading I urge you to rethink your requirements.
That being said. Here are some tips:
My understanding of Service#onTaskRemoved(Intent) is that it is only executed if you kill the app through task switcher, so I don't know if this is useful to you. In your instance I would keep a activity ref counter in the application object (+1 for every onResume(), -1 for every onPause() of any activity). With this you can check if your user has active UIs. Usually if you pressed back on the last activity that comes as close to the paradigm "closing" an app. Then just start your task at that point from the application object (this will probably be the last to get gc) or if that doesn't work try an unbound service the most uncoupled component you can generate.
Another, very very bad solution is overriding the finalize() method in an object (e.g. your activity). There are only very, very few reasons to use it since it will trigger an additional gc cycle and your code will be run on the main thread, but it is a way to execute code if the object is about to be gc'ed. Therefore it is discouraged to use by the android team, only use it if you have a gun up your head.

Handle application states (starting/stopping) not activity states

I'm working on my 1st Android app and wondering how to handle activation/deactivation/starting/stopping globally, not on Activity level.
This great article shows states transition for Activities:
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
Is there something similar for Application states?
For example at iOS and Windows Phone app there is clear app states separated from activities (views, controllers, whatever).
I'm asking because I want to perform certain operations only once per app loading/exiting not with every activity starting/stopping
The answer is There is Simply No Direct method to do this
rather than in Application Class you can catch these events
#Override
public void onLowMemory()
{
super.onLowMemory();
}
#Override
public void onTerminate()
{
super.onTerminate();
}
So you will have to handle it in all the Activities you will be having
the following methods
onResume()
onStart()
onRestart()
onPause()
onDestroy()
You will have to implement in all Activity to handle for all application
A suggesstion
You can have some Variable in Application class to save application state
say create a variable like
public static boolean isPaused;
and set it from all activity on state change
The question you're asking is applicable for iOS and Windows but not really for Android.
Android doesn't really have a concept of an application as an object, although there's an Application class. Instead, an app is a loose collection of Activities. There are many good reasons for this state of affairs; for example, it supports fast app switching and easy interaction between Activities of different apps.
The best way to coordinate your "app" so that one Activity doesn't try to do something that's already been done is to use SharedPreferences to store app state. Nearly every other way of doing it is less preferred. Even if the system kills off your entire app, SharedPreferences will maintain the current state. The Application object won't.
Also, Android is based on pausing and resuming. An Activity or activities are created, pause, and resume. They may be destroyed, but that's an extreme case. A corollary to this is that apps should not have an exit button; there's no need for one. I sometimes see apps that have one, but what they're really trying to do is shut down a background Service or process. The best way to do that is to have an affordance that says "Sleep" or similar.
Have all activities inherit from the same hierarchy and put whatever you want in OnCreate, OnPause, OnResume, OnStop, OnDestroy and call the super where applicable.
Example
Parent
IamTheParentActivity : Activity
protected void onCreate()
{
setApplicationState(ApplicationState.Running);
}
protected void onPause()
{
setApplicationState(ApplicationState.Paused);
}
private void setApplicationState(Enum ApplicationState)
{
//Some Application Level Variable
Application.State = ApplicationState
}
Children
IamTheChild : IamTheParentActivity
protected void override onCreate()
{
base.OnCreate;
do other stuff
}

Application class onCreate method not running on starting app 2nd time

I am using Application class to share global variables across activites and I am setting them in onCreate method of application class. When I start app variables values are set in onCreate and while using app in activities I am changing values of varables. When I exit app and start it again I am getting old values, the last values of variables set in activities. Thats mean onCreate of Application not running on starting app again. This is code in onCreate method of Application class.
#Override
public void onCreate() {
super.onCreate();
application = this;
category = 12;
subCategory =22;
}
It looks like old application object is still in memory and it is not calling onCreate on starting app 2nd time.
What is need to be done so that onCreate of application class run again or where to initialize variables in application class so that code runs everytime.
please declare your application class name in manifest file.
like below
<application
android:name="com.tt.app.TTApplication"
android:label="#string/app_name"
In the Application class, the onCreate() method is called only if the process was ended when you exited the application. Usually the process is stopped when the system needs memory or if you exit the app using the back button instead of the home button. However, you cannot rely on it being terminated.
However, the right way of passing parameters between activities are intents or preferences. In your case, I have the feeling that preferences is the way to go.
If you really want to kill your process when exiting the application, you can call
System.exit(0); when the user presses the back key on your first activity. This is definitely not recommended since it means fighting against the way the Android OS works and might cause problems.
More on this here: Is quitting an application frowned upon?
There is probably an instance of your application still in the memory.
Recheck your life cycle methods and make sure that the application is exiting properly.
Also check if any of your activities are leaking memory.
I had the same problem with my app where onCreate() method of Application class just triggered for the first time when my app is loaded. Daniel's solution of using System.exit(0) did the trick but this solution lead me to another problem. After using System.exit(0), onPause(), onStop() and onDestroy() method of my foreground activity did not get called.
Well, that was a reasonable behavior for an app because If you use System.exit(0) then you application will be removed from System's process queue and there will be no way for an android to execute onPause(), onStop() and onDestroy() method for my foreground activity.
The workaround I used for this problem was to finish my activity when back button is pressed and after some time killing my applications process like below:
public void killApp(){
final Thread threadKillApp = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "Going to kill app");
android.os.Process.killProcess(android.os.Process.myPid());
}
});
threadKillApp.start();
}
Calling killApp() method just after calling finish() on my activity did the job.
Check the Activity life cycle. Do what you want in onResume() instead.
try to use onStart() method or onResume().
Your onCreate method should look like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(someView);
}
your onResume Method should look like this:
#Override
public void onResume() {
super.onResume();
variable = someVariable;
}

Android - How to track app Resumes only when you exit and come back to the app?

I have an issue. For analytic purposes I need to track when the APP (not activity) is resumed. The problem I have now is that if I put the tracker on the OnResume event of an activity, it will get fired every time the user goes back and forth on different activities.
How can I avoid that? How can I track the real "Application Resume," (when user actually exits the app and come back) and not the activity resume?
Any ideas is greatly appreciated. Thanks.
I encountered the same problem and solved it by creating base activity :
public class mActivity extends Activity{
public static final String TAG = "mActivity";
public static int activities_num = 0;
#Override
protected void onStop() {
super.onStop();
activities_num--;
if(activities_num == 0){
Log.e(TAG,"user not longer in the application");
}
}
#Override
protected void onStart() {
super.onStart();
activities_num++;
}
}
all the other activities in my app inherited mActivity. When an activity is no longer visible than onStop is called. when activities_num == 0 than all activities are not visible (meaning the the user close the app or it passed to the background). When the user start the application (or restarting it from the background) onStart will be called (onStart is called when the activity is visible) and activities_num > 0. hopes it helps...
Use the Application object of your app (see http://developer.android.com/reference/android/app/Application.html). If you create a custom Application class and configure it in your AndroidManifest.xml file you can do something like this:
Start tracking in the onCreate() of the Application object.
Instrument all your Activities so their onPause() and onResume() methods check with the Application object and see if they are the first Activity to run, or if they are continuing a previously running instance of the app.
Stop tracking in the onDestroy() of the Application object.
To a certain degree most of the analytics packages (Flurry and their ilk) do something similar to this. You'll need to do a little state machine work to get this to work right, but it shouldn't be too complicated.
Instead of OnResume(), hook into the OnCreate() event of your main activity.

Categories

Resources