Search code examples
androidandroid-lifecycleandroid-instant-run

How can I cause the Android Application class to be recreated?


Application class: Sometimes it's recreated

Tell me if I have this right: When starting an Android application, if there's a class that extends android.app.Application, that class will be created when the application starts. But if the application is not being used, then that instance may be deleted and later recreated when the application comes to the foreground again. So if there are any instance variables that were initialized before, those variables are no longer set.

Testing robustness of recreation of the Application instance

This question is about how to test to see how well an application survives the process of having it's application class recreated.

I have found that I can go into an activity in my application, then switch to other applications for "a long time" (on the order of hours), and when I come back I see that the constructor runs in my class that extends android.app.Application. The problem is that I don't know how to force this recreation so that I can test efficiently.

Restarting from various activities

I'm adding this paragraph to the original question to call attention to the testing I'd like to undertake. I'd like to expand upon above, where I said "...go to an activity in my application, then switch (away from my application)...". The idea is NOT to kill the whole application and start 'from the top'. The user is inside an activity that, if the Application instance survives, might behave one way, but if the Application instance happens to be recreated, then might behave another way.

I'm not asking for the following problem to be solved in this question (it's covered elsewhere). I am asking for a process whereby problems like this can be uncovered in testing. So the example: let's say that an instance variable is saved in the Application instance when the initial activity runs. Classes that need that variable can get it from the Application instance, but only if the initial activity has set it already. Now the OS decides to wipe-out and recreate the Application instance. When the user brings the app to the foreground, and they're running some random activity (never going through the onCreate() of the initial activity), the instance variable is null. If the activity is well-coded, it will not just crash with an NPE. So I'm trying to test to make sure that in the above situation, where the instance variable is null, that the app behaves nicely. I THINK I've got it, but I'd like to make sure, and I'd like to make sure no matter what activity is running when the user puts their phone down.

What the log looks like

If the application is left at one of the child activities and application is put in the background for a "long time", the OS destroys some class instances. When the application gets focus again, there are some creation processes. Here is what the log looks like.

I/zygote: Late-enabling -Xcheck:jni
V/DaleApplication: DaleApplication constructor.
I/InstantRun: starting instant run server: is main process
V/DaleApplication: DaleApplication onCreate. 
V/DaleDatabaseAdapter: constructor.  
V/DaleListActivity: onCreate() is pulling records from the database.
V/DaleListActivity: >>>>>> Selection Args T

You can see I put logging into DaleApplication which extends android.app.Application. As an aside, we also see it also recreates the database adapter and starts pulling records from the database, putting the user right back where they were before all these objects were destroyed.

The answer I'm seeking in this question would be some process that I could undertake that would allow me to cause the class instance destruction on demand, thus allowing me to validate that the rebuilding process is sound.

What I've Tried

Although I figured that killing the whole application would not work, an answer below suggested I try it. But of course I need the activity that the user was using at the time the phone was set down to resume.

1) I tried kill via adb:

After getting my adb.exe command line working, I was able to get the pid for my app using adb shell, then pidof ..(aid).., where ..(aid).. is the ApplicationId in build.gradle. That returned 13488.

I tried to kill the application using am kill ..(aid).., but that said nothing, and the pid was still there. I tried kill 13488 but that said Operation not permitted. With a -9 didn't help.

EDIT: I finally got this method to work after finally straightening out which instance of adb.exe to interact with. It was equivalent to pressing the 'Terminate App' button [see item "3)", below].

2) I tried hitting the "red square" in debug tool window:

In the debug tool window, I selected "Threads". There were a bunch of things in there. I had no idea which thread to stop that would emulate the user putting their phone down for an hour. After stopping main, when I went back to the application on my phone, the application started the main activity (not like when just the Application class gets recreated, which starts whatever child activity was running earlier).

EDIT: I think this is not a good approach, but there might some thread here that doesn't cause Android to start the previous activity instead of the last activity. Did not investigate more because this answer solved the problem for me.

3) Terminate App button in Logcat:

I was able press the 'home' button on the phone, then hit the "red square" in the logcat window, but that put me at the activity before the activity I was on when I pressed the home button.

Terminate App button in Logcat

From what I understand when you terminate the app from Android Studio (logcat), Android presumes that the current activity is not well-behaved, so instead of starting it, it starts the previous activity. This doesn't match the behavior of when the phone is set aside for a long time and then the app is restored to the foreground.


Solution

  • The easiest way to test your application to see if it survives well when the OS removes things is to configure your testing device to not save things in the first place. This way, every time you hit the home button the OS will not save anything.

    If you go into Settings > System > Developer Options > Apps, you should see:

    • Don't keep activities <<< Turn this on
    • Background process limit <<< Set this to 'No background processes'

    Developer options to not save background things