Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 410
Dale Avatar asked Sep 05 '25 10:09

Dale


1 Answers

When starting an Android application, if there's a class that extends android.app.Application, that class will be created when the application starts

More accurately, an instance of that class will be created when your process is created.

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.

More accurately, your process can be terminated at any time when your app is not in the foreground (and, on rare occasion, even when it is in the foreground). All of your objects, including the Application singleton, go away when your process does. Your next process will have its own Application singleton.

So if there are any instance variables that were initialized before, those variables are no longer set.

That depends a lot on when they get initialized. For example, if you initialize them in onCreate(), they will be initialized again in new instances of your Application subclass.

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

Terminate the process. In Android Studio, the red square "stop" toolbar button does this. You can also terminate the process from the command line. In many cases, swiping your task off of the overview screen will terminate your process.

like image 163
CommonsWare Avatar answered Sep 07 '25 23:09

CommonsWare