I need to completely free the memory which was in use by an Activity when the user closes that Activity. will using
android:noHistory="true"
be enough?
By saying
android:noHistory="true"
you tell android not to keep a reference of your activity inside the back stack of activities. That's already a good start.
The only thing that remains to be done is to be sure that you don't keep a reference yourself to your activity. For instance, don't :
store your activity's instance as a static data field. It would not be garbage collected as classes are not.
store your activity's instance as a data field of a singleton. (As transitively a singleton instance is a static data field). And so on.
If you don't keep any reference to it, and add the noHistory flag, then you can be sure it will be garbage collected.
Also, note that you can use MAT with eclipse to get sure that there is no instance of your first activity as soon as you reached the second activity.
Related
Problem: Sometimes / on some devices the activity calling startActivityForResult (activity A) to launch activity B is being destroyed after calling startActivityForResult & before entering onActivityResult. We get a newly created instance of activity A to return to in onActivityResult - this causes our ViewModel (along with all other member variables) to be lost.
The standard thing to do would then be to restore the ui state using SavedInstanceState. This can't be done in this case due to the size of the object we need to restore - attempting this results in a TransactionTooLargeException. The ViewModel is too large for a Serializable or Parcelable.
Question: Is it possible to force our Activity to be kept intact during this workflow? Or is there another design that would let us avoid this problem? Saving any of the ViewModel's data to disk is not an option.
Context: This is a project where we store a list of images (as byte arrays) taken from the camera one at a time, and some related info about those images in a ViewModel. These are staged in a RecyclerView, where they can be uploaded when the user is done adding images. We add items to this ViewModel by calling startActivityForResult to launch a camera activity and return the resulting image.
We may only be seeing the problem of activity A getting destroyed due to the "Do not keep activities" setting in Developer Options being turned on, and this may not accurately represent how Android would reclaim resources (e.g. the conversation at the bottom of this thread - https://stackoverflow.com/questions/21227623/whats-the-main-advantage-and-disadvantage-of-do-not-keep-activities-in-android#:~:text=Android%20OS%20has%20this%20property,replicate%20the%20same%20scenario%20easily). Still, ideally we want everything to work with this setting on. Right now if activity A is destroyed, we lose our member variables and the ViewModel that we were in the process of building, and don't have a way to recover it.
Storing the ViewModel's data in a fragment (as discussed here: Fragment, save large list of data on onSaveInstanceState (how to prevent TransactionTooLargeException)) won't work since our activity is being destroyed, causing any associated fragments are as well. We actually have a fragment we're using in this way, which loads & holds a list of objects from the server to be selected from and associated with each image - this fragment ends up getting recreated along with the activity when its destroyed and then performs this load again.
No, what you want is not possible. If you launch another Activity using startActivityForResult() and that Activity requires resources, the launching Activity will be killed. There is nothing you can do to prevent this. It is standard Android behaviour and will happen, especially on low-end devices.
If your ViewModel is too large to save as the instance state, you will need to put the data somewhere else: SQLite database or a local file. Then store the name of the file or some key to the database as part of the saved instance state, and when the Activity is relaunched, restore the data from the file or data base.
Note: you shouldn't keep that much data in memory anyway, as you are wasting valuable resources. Only keep the data you really need in memory.
I have an object which I know is persist, because it performs it's behavior. It is an extension of RecyclerView.Adapter with SelectionTracker inside, which I am connecting to my RecyclerView only once. After I rotate my screen, Activity recreates itself and all member fields turn to null, including field with extension of RecyclerView.Adapter. But it is still somewhere there, because RecyclerView still works and I can select and deselect items.
How can I reacquire a reference to this object?
I don't want to serialize or parcealize it, because it is in memory and working.
Also I wonder, under which circumstances Android will dispose objects in such a situation?
You can solve this in 2 ways:
Tell Android that your app will handle the configuration change itself by adding android:configChanges="..." to your manifest. In this case, when the screen orientation changes, Android will not kill and recreate your Activity, it will simply call onConfigurationChange() on the existing instance and you can manage it yourself.
Use onRetainNonConfigurationInstance() and getLastNonConfigurationInstance(). Upon an orientation change, Android will call onRetainNonConfigurationInstance() just before it kills the current Activity. In this case, implement the method and return this (the instance of the current Activity) from the method. Android will then kill the Activity and create a new instance. In onCreate(), you should call getLastNonConfigurationInstance(). If this returns a non-null value, then this will be a reference to the Activity that got killed. You can now copy any data from member variables in the old instance to member variables in the new instance. In this way, you can take "migrate" anything necessary from the old instance of the Activity to the new instance.
I would like to determine if this is bad practice, since I have implemented this in some locations.
I have two activities, MainActivity and SecondActivity.
If I want to transfer the string "Hello" from Main to Second, I use a class called Transfer. In this class I have a static String that I set to "Hello", which I access from the onResume method of SecondActivity.
How does android manage the "Transfer" class? Is it tied to MainActivity and destroyed along with it? Is there any other behavior I should be aware of?
Given that the String field is static, I'd say is bounded to the whole process and not to the MainActivity.
The problem is, the android os might free your app's resources to start another process.
What may happen is that your app gets backgrounded, the os needs it resources and frees the memory, and then the user gets back to SecondActivity. The process gets recreated and the previously initialized static field is now null.
If your need is to pass Strings between activities, I would bundle them into the intent's extras.
Static members exist as long as the app is in the memory.
This approach works fine. Another way to share data between two activities is to make use of putExtra to put data into second activity and getExtras to get the data.
Initially I didn't pay a lot of attention to the possibility of memory leaks in Android, given the nature of managed code / garbage collection and so on. I'm thinking this might have been a bit naive. Here's the question:
Say there is an activity - MyActivity. When the OS starts it, in its onCreate() this instantiates another class (MyOtherClass) and keeps a reference to it. However say the instance of MyOtherClass also keeps a reference to the context - which happens also to be a reference to the instance of MyActivity.
Now something happens - say the screen gets rotated. OS calls the activity onDestroy() and drops the reference to that old instance of MyActivity. However, that activity instance still has a reference to an instance of MyOtherClass, which in turn has an instance to the activity.
So, am I right in thinking those two classes are going to keep each other alive for evermore?
If so, I guess possible answers are (a) don't keep a context reference, get it another way, or (b) in the activity onDestroy() drop any references it has to anything else, then it all ought to just collapse.
Java wouldn't allow cyclic links to keep each other alive (in memory). However if you have declared references static or created singleton style objects, Java won't help you there.
A good start might be reading avoiding memory leaks.
This is not my code. I just arrived at this site and am doing code review.
They have a class which is an extension of Dialog.
It has been defined as a singleton.
On the first call the context is passed to the getInstance method.
It instantiates the class passing the received context to the "super" within the constructor.
Then it saves it - same as in any singleton.
It then displays the dialog. After user interaction it starts a new activity and closes the dialog via "closeDialog".
However, it is still alive since the static holder for the instance is still there.
Will this then hold on to the activity that created it (and was passed on the "getInstance" call and into the "super()" when creating the instance)?
They keep the instance alive because they then use it for calls from other places and have values that need to be carried over.
I know this code stinks but I want to be sure that it does leak memory (the first activity) before I make them re-write it (or re-write it myself - which is more likely).
Yes it could. If the code starts other activities, then yes. If only the one activity is ever used, then most likely not. The reason being, dialogs must be instantiated with an activities context (it'll crash with the Application context). If that activity is set to be destroyed, garbage collection won't clean it up until all references to it are destroyed. If this singleton dialog lives outside the activity (which should be the case), then it'll continue referencing the activity and prevent GC from cleaning it up. You can read more about leaking contexts here: Avoiding memory leaks
As you stated the code is bad, and using a singleton dialog like that is just plain wrong (whether it leaks or not). There are better ways of maintaining data between states.
Instead of creating and holding Dialog inside Singleton class, build the dialog in that Singleton class but return Dialog instance to the caller class. So calling Activity will be responsible for dismissing Dialog and i believe there will not be memory leak.