Let's say we have a reference (strong reference) to an activity object.
What happens to Activity object after it was:
finished or
changed orientation or
put on pause or stopped because of switch to another activity
I am talking about a case when application wasn't killed by OS but when a user continue to use the application.
Will activity ever be released, if we continue to keep this strong reference?
One one hand, as I understand, if somebody keeps a reference to an object it can't be released/deallocated. On other hand, Android is quite aggressive with releasing unused activity and I wonder whether Dalvik machine has some exception which will allow to release/deallocate an activity which is referenced.
These article doesn't talk directly about a case, when somebody is keeping a reference:
http://developer.android.com/training/basics/activity-lifecycle/starting.html#Destroy
http://developer.android.com/reference/android/app/Activity.html
There is only one hint which I got:
There is a method Activity.isDestroyed() which kind of implies that object won't go away immediately.
Related
I've read many articles about how bad global variables in the application class or in Singletons are. The biggest issue for me was that it causes a NullPointerException when the app gets killed by the system and the user restarts it. The app restarts with the Activity where the user was before and not with the first Activity of the app. The global variables don't stay in memory forever so starting the last Activity causes a NPE (if you don't check for null manually).
All those examples are using apps with multiple activities though. Does this problem still exist with single activity applications?
I've tried to replicate the NullPointerException in my app but on all my devices the app restarts with the first fragment and therefore the app does not crash.
Yes, they do. The reason why it didn't crash my app was that I had no fragment where I accessed the singleton's data without creating it first. I fixed it by replacing the singleton with a room database.
If I have a reference (in a non-activity class) to an Activity that isn’t currently being displayed, is there any reason that I shouldn’t use it start another activity?
Example:
Activity A:
Intent anIntent = new Intent(this, ActivityB)
startActivity(anIntent) // happens first
Some Other Non-Activity Class:
Intent anIntent = new Intent(refToActivityA, ActivityC)
startActivity(anIntent) // happens second
You generally shouldn't hold references to Activities or other contexts unless you have a good reason to do this.
1) If your first activity is no longer being shown, it's subject to being killed by the system and garbage collected. If you hold the reference, though, it can't be garbage collected, resulting in a (potential) memory leak.
2) Saving a reference to an Activity means you're coupling that class to that activity, which is generally bad practice.
3) Launching activities is an Android concept and should generally be controlled by other Android components. Unless your class is some navigation abstraction, it probably shouldn't be starting activities.
Without more information, it's hard to say what you should be doing in your specific case, but generally you should use the most local Context to start the activity (which could be a Service, ContentProvider, BroadcastReceiver, etc) and not hold on to Contexts.
Hope that helps.
The quick answer is don't do it.
You have a reference to an Activity that is not being displayed. For all you know, that Activity could be destroyed. The fact that you have a reference to it doesn't guarantee that it'll be in a valid state. Trying to use it may throw an Exception.
Personally, I hate seeing a crash/ANR popup for an app that I'm not actively using.
Arguably if the activity is in a valid state and you are able to use it to launch the new activity, it's an even more annoying experience for the user: You're hijacking whatever they're doing (which is likely outside of your app now) to bring to foreground another activity from an app that they've recently closed.
Bad experience in both cases.
Then again without knowing exactly what it is you're trying to accomplish, it's hard to give a definitive answer. Perhaps reword your question and say what you want to accomplish.
I noticed this behavior while developing a simple Android game which has 2 activities.
The game has 2 activities, the first is a screen which allows the user to select the opponent type, level etc. and the second the actual game screen.
The second activity creates an object of a GameManager class which handles all the game processing.
This GameManager class also creates a CountDownTimer which it starts to prompt user input (on timeout the game is defaulted to the opponent).
I've noticed that if the user exits the second activity (returns to the first) and then launches a new game again, the previous timer is still running until completion.
I've handled this by explicitly cancelling the timer (from the onDestroy() of the second activity) as just setting the timerobject to 'null' did not cancel the timer.
However I'm curious as to why the previous timer was running even after my activity was exited the first time? Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited? Would be great to know the reason behind the observed behavior?
TIA
Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited?
This isn't how Garbage Collection works. The GC isn't responsible for 'deleting objects' - it's responsible for picking up 'orphaned' objects and freeing their resources. Even then, a GC isn't guaranteed to get to all of the orphans in a timely manner.
Further to that, any objects which may be 'system' objects and need to be released explicitly may never be released if your code doesn't do it. Other issues with GC may include creating objects which other threads (other than the Activity which created them) may have a reference to.
You mention your 'timer' but don't explain what sort of class you are using for it. I suggest read up specifically about that class and see what the implications are for ceation/deletion (possibly explicit 'release' of resources).
GC is a very grey area on any platform. With Android it's normally pretty immediate but with the nature of the Activity life-cycle it's very difficult to predict what will happen.
In general make use of onCreate, onPause and onResume within Activities and also things like savedInstanceState and SharedPreferences to keep track of what is going on.
CountDownTimer is not bound to an activity as you already found out. A hint to lookout for in these cases is that a class does not receive any Context in its constructor. Hence it can't be bound to an activity.
I have a fairly complex app -
The UI Activity launches a Service and sets up 2 way AIDL callbacks so the two can communicate.
The service runs forever (unless hits 'off' button in UI Activity).
The problem is when the user exits the Activity, the Activity memory is not released.
-The amount of memory used by my app is the same even if the UI Activity has been closed.
-The heap still shows mapTiles and other UI crap on it even if the UI Activity has been closed.
So my guess is somehow the Service is holding references to the Activity. I know the many articles warning about leaking the Activity Context. The Service only references the Activity through a Weak Reference stored at Application scope. (a class that extends Application)
Is there any way to find what specifically is referencing the Activity? The dominator tree shows mapTiles and ListView layouts eating all my memory... but I can't find the reference to the Activity which is keeping that stuff alive.
Also, is there a way to dump an HPROF heap dump thing if OutOfMemoryException occurs?
The problem is when the user exits the
Activity, the Activity memory is not
released.
There is no "exit Activity" in Android. Calling finish() or pressing back on the activity does not remove objects from memory that the activity used. Android inherently takes care of this itself at some random point in the future.
If you want your objects to be released from memory at the moment the activity finishes, you need to manually release them yourself.
Edit: The class that can be used to find memory usage is the ActivityManager.
If it's not yourself who is holding a reference ("references the Activity through a Weak Reference stored at Application scope", do you null it? I wonder why you reference the activity in the service, usually its the other way), did you try to execute a GC? As long as there is enough memory left, no gc will take place to move the trash away.
In my application, I use a subclass of the Application object to store some references to complex objects I need to access from all of my activities. When my app starts, the startup activity checks one of these references, in this case a Location, and if it is null, it starts the LocationListeners which populate the reference for further use.
If I back out of the app to the launcher screen, and re-launch it, the Application object still has the reference from the previous use a few moments prior. This is fine, and is what I'd expect, but I'm curious how long the Application object is kept around once I've back'ed out of my application? (onDestroy() has been called on all activities, nothing in the stack.)
When is it finally killed? I know it does finally get killed as when I've not used the app in a while, it will search for location on startup (indicating the aforementioned null reference.)
(Also, is storing refs there like that a good idea?)
Thanks in advance gang! :-)
It stays around as long as the application is in memory. It only finally goes away when either someone forcible terminates your application (either using a task killer or from the application settings) or when Android decides it wants to reclaim the memory that your app is using (and this typically only happens when your app has been closed for a while and the phone is running low on memory).