Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When static resources are killed, are they all killed or can some remain in rare edge cases?

Tags:

java

android

Note: While the two answers provided so far (on September 6th) are interesting, they unfortunately don't address the question.

One of my Android test devices is a HTC One X. This device is known for frequently killing background applications (even including the launcher, most infuriatingly) because it tends to live on the edge in terms of RAM allocation, presumably due to HTC bloatware. However, for my purposes, this has been extremely useful as it has helped to highlight the effects of various low memory situations and allow me to improve my application to cope with such events. One of the things I have learnt, for instance, is that the Application instance and other static resources can be killed even though the Activity backstack is retained. So, to give a good user experience, the backstack can remain even though the single process running the application, and all the statics it holds, has gone. For this reason, my application is now very rugged in terms of gracefully checking the state, and actioning the re-initialization if necessary, of the "Singleton" data it needs on the resuming of any Activity.

To move onto my specific question, I have been seeing a rare symptom that, through code inspection, I believe could only have been caused by a static member of one class having been killed and then subsequently re-initialized, while another static resource in one of my library classes has not been re-initialized. I appreciate that such a dependency between two separate static resources represents bad design on my part, and I will refactor to avoid this. However, I would like to know if I could possibly be correct in my analysis - that is, is it possible to have a sitation where the backstack is retained, but only some static resources are killed, particularly on a per-library / package basis?

Edit 1 I'll give a bit more information about the two classes concerned.

Class 1 is a class we'll call Controller. It's not used as a Singleton, but contains a static Map of data to be common across all instances. It's initialised like so:

private static Map<String, String> sSomeMetaData;

static {
    sSomeMetaData = new HashMap<String, String>();
}

Next, I have a class called MyFlyweightFactory. This class lives in a separate library. This class is a Singleton:

private static MyFlyweightFactory instance = new MyFlyweightFactory();

public static synchronized MyFlyweightFactory getInstance(){
    return instance;
}   

private MyFlyweightFactory(){ }

TreeMap<String, MyParserRenderer> images = new TreeMap<String, MyParserRenderer>(); 

Now, here is the dependency. The factory class has a getter method to obtain a certain named image object which is constructed by parsing a file from the file system. If the factory hasn't been asked for that image since factory initialization, it parses it from an file (it's actually an SVG image parser library of mine). The image is parsed into a MyParserRenderer object. When this image parsing happens, the factory also populates some data in the Controller class' sSomeMetaData member. All of the images that the factory holds onto are kept in the images member TreeMap you see above. So, these images are a non-static member of a static Singleton factory instance.

The rare problem situation seems to be that instances of Controller find that sSomeMetaData is empty, even though I know that MyFlyweightFactory has provided some objects from its Map. This could surely only happen, I believe, if the intance of MyFlyweightFactory has stayed around and therefore didn't need to re-parse the image objects (which means that it will not populate sSomeMetaData ever again), but in the meantime the static initializer of Controller has since executed again. I can confirm that sSomeMetaData is not being clear()ed anywhere else in code.

like image 507
Trevor Avatar asked Sep 06 '12 11:09

Trevor


2 Answers

You should take a look at this: Activity lifecycle.

enter image description here

When you are out of memory, paused activities will be killed to free memory.

Hence why you should try and account for this in every situation that you have to re-create the activity.

This is not a whole app, but on an activity basis. So it will start killing activities that it feels are less important. Some activities may be affected, others not, in the same app.

Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may killed by the system at any time without another line of its code being executed. Because of this, you should use the onPause() method to write any persistent data (such as user edits) to storage. In addition, the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state, allowing you to save away any dynamic instance state in your activity into the given Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created. See the Process Lifecycle section for more information on how the lifecycle of a process is tied to the activities it is hosting. Note that it is important to save persistent data in onPause() instead of onSaveInstanceState(Bundle) because the latter is not part of the lifecycle callbacks, so will not be called in every situation as described in its documentation.

like image 52
IAmGroot Avatar answered Nov 16 '22 04:11

IAmGroot


I think you are somehow on the wrong track in debugging or tracing the problems in your Application.

Here is what I can tell you, and what I think that you understood wrong :

When your application is destroyed by Android because it needs resources, your Application class will be also "destroyed/stopped" and the backstack retained. When you re-launch your application, your specific Application class will be 're-created' (onCreate() will be called) , and your Activity back stack, will also be re-created, this meaning that the last Activity that was visible to the user will be re-created. So basically, what happens in your application, is the expected behaviour. Why some members in a library don't get re-initialized... I can't figure it out.

I also had a similar question here : Application restart - Activity Entry Point

like image 39
Ovidiu Latcu Avatar answered Nov 16 '22 02:11

Ovidiu Latcu