How to call a method when an Android app is closed

2019-04-01 00:05发布

问题:

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;

  1. Why does it destroy the Activity when the app is not finished?
  2. And more importantly: how can I run my CleanUp method when the app closes or loses focus?

回答1:

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.



回答2:

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.



回答3:

You can't do this (call a function) in java part of app. Only in the native part.



回答4:

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);