简体   繁体   中英

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.

在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.

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.

1.) Put the app in background with HOME button

2.) Terminate the app from Android Studio

终止按钮

3.) Restart the app from the LAUNCHER on the device

Enjoy!

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.

Actually, that has nothing to do with "not being used", the whole process is being terminated by Android.

You can persist things across process death with onSaveInstanceState(Bundle) , then restore it in void onCreate(Bundle savedInstanceState) where savedInstanceState != null .

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'

开发人员选择不保存背景的东西

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM