Memory leak in android.os.Message and/or Handler.removeCallback? - android

I have an activity that looks like the following:
class MyActivity extends Activity {
Runnable refreshTimer = new Runnable() {
public void run() {
refresh();
}
};
protected onCreate(...) {
handler.postAtTime(refreshTimer, ...);
}
protected onDestroy() {
handler.removeCallbacks(refreshTimer);
}
protected void refresh() { ... }
}
After onDestroy is called, there are still messages in the activity's MessageQueue that contain references to MyActivity$0 (the refresh Runnable) for some reason. Because MyActivity$0 has an implicit reference to MyActivity, this causes a memory leak of the MyActivity context.
The result of merge_shortest_paths for android.app.Activity excluding phantom,soft,weak,etc references using Eclipse Memory Analyzer Tool:
(The source code above is a simplification of the actual object relationship displayed in the MAT dump)
Shouldn't calling removeCallbacks remove any references to the runnable objects from the Queue? Why am I leaking contexts?

Something to try:
According to the android docs:
OnDestroy:
The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
When you are exiting your activity, it looks like there are still a bunch of queued up messages and the context for unregistering is not invoking the cancel callback.
What you should do is unregister your runnable in onPause:
This callback is mostly used for saving any persistent state the activity is editing, to present a "edit in place" model to the user and making sure nothing is lost if there are not enough resources to start the new activity without first killing this one. This is also a good place to do things like stop animations and other things that consume a noticeable amount of CPU in order to make the switch to the next activity as fast as possible, or to close resources that are exclusive access such as the camera.
Typically a Receiver or "Scheduled" Runnable will register in onResume, and unregister in onPause for better lifecycle pairing
Without seeing what you are doing in refresh, it is tough to tell, it could be leaking due to activity references that are activity scoped referenced in the refresh method.

Related

Android lifecycle, which life cycle methods are executed in the same message during orientation change?

I need some confirmation on some information I just found out recently.
Are the lifecycle methods onCreate(), onStart() and onResume() handled together as ONE message in the message queue during an orientation change?
and on the flip side is onPause(), onStop() and onDestroy() handled together as one message?
One of the reasons I wanted to know is that if I have a thread that loops infinitely while posting to the main ui thread and I change my orientation, will it always post after onResume()? It will never post BETWEEN a lifecycle method right?:
private static class MyThread extends Thread {
#Override
public void run() {
while (true) {
mainUiHandler.post(myRunnable);
}
}
}
Thanks!
No. At least not as something you can rely on. Remember that onPause can be called without onStop in some cases. Same for onStart without onResume. (in both cases they'll be called eventually if needed). onDestroy may never be called at all, your app should be written assuming that it won't be for sure.

Android lifecycle and external threads

I've been staring at my app's log file for a couple of hours and just want to make sure what I see is even possible.
I have an Activity called ActivityA.
It starts up ThreadB.
ThreadB communicates with a server and sends the results back to ActivityA.
I am logging messages in ThreadB when it receives results from the server and sends them back to ActivityA
I am logging messages at the start and end of ActivityA's onDestroy() method.
Here's the weirdness.
ActivityA's onDestroy() method completes. I know it completes because I see the message I print at the end of it in the log.
Then, ThreadB gets some very late input from the server. ThreadB delivers it to ActivityA.
The routine in ActivityA that ThreadB communicates executes. I know it executes because the messages it displays as it runs show in the log file AFTER ActivityA.onDestroy() has completed.
I thought once onDestroy() completed ActivityA would be unreachable. IOW ThreadB could send messages to ActivityA as much as it wanted but ActivityA would not receive these messages because it didn't exist any more.
What in the world am I missing?
You are mixing the Object lifecycle and Activity lifecycle.
If you hold a reference to an Object (the activity in this case) you can execute methods on it.
The Activity lifecycle controls things on a higher abstraction level, determining if it's executing, being presented to the user, etc. It does not control whether methods can be invoked on the Activity object.
You can see this with a simple example:
public class DummyActivity extends Activity {
public int nothing() {
return 1;
}
}
DummyActivity act = new DummyActivity();
act.nothing();
Here I create an Activity and call a method. It does not matter what's the state of the activity, it's only relevant if the object was created and I hold a reference to it.
This might be happening because the ThreadB is a non static inner class of ActivityA, so it has reference to ActivityA, that is why ActivityA is not getting garbage collected. Even if its onDestroy() method is called.
JVM keeps the reference to the currently running thread, and ThreadB in turn has reference to ActivityA. So method of ActivityA gets executed even after onDestroy().
Make the tread as static inner class in your Activity and do not forget to stop your thread in onDestoy(). This would stop the method of ActivityA get executed after onDestroy().
Callback onDestroy does not destroy object Activity, it's still safe to make calls to methods inside some Activity, Fragment or whatever after onDestroy called if you do not touch view elements.
By the way expected behaviour can be reached via Intents and BroadcastListener.
Just implement BroadcastListener with action "my.log.intent" in your activity, register it onStart() and unregister onStop().
Then send broadcast from your logger:
Intent intent = new Intent("my.log.intent");
intent.setExtras(someUsefulData);
LocalBroadcastManager.getInstance().sendBroadcast(intent);
and there you go:
your someUsefulData will be available to Activity regarding activity lifecycle. I.e. when activity visible to user and you are able manipulate contained views.

Concurrent Instances of Activity in one application?

I have an Android application with a single Activity (MainActivity). I also have a static state variable (foo) that needs to be started and stopped with MainActivity. The lifetime of foo must match the entire lifetime of MainActivity, not its visible lifetime, nor its foreground lifetime. Here's the basic gist:
static Foo foo;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
foo.start();
}
protected void onPause()
{
super.onPause();
if (isFinishing())
disposeFoo();
}
protected void onDestroy()
{
super.onDestroy();
disposeFoo();
}
private void disposeFoo()
{
if (foo.isRunning())
foo.stop();
}
Every now and again I will get a crash report that says: Foo has been started while already running.
I can start and stop MainActivity all day long from the app launcher and this crash won't occur. As far as I know, no one is calling startActivity on MainActivity either.
Is it expected behavior that a new instance of MainActivity will be created, and onCreate called on it before the onDestroy is run on the old instance all within the same application? In what circumstances would this occur? Is there a different pattern I should be using to initialize libraries, databases, and other singleton objects?
Your app is in very often killed if some other application with higher priority (generally, if it's in the foreground it's higher priority) needs the resources. This is due to the nature of mobile devices having relatively limited resources. You will find that it's static variables may be null once you return to it, so static variables for a longer periods of time in Android is a bad idea.
You should save your data somewhere more durable. You might find this article on general Data Storage to be useful. This question should be relevant too: Saving Android Activity state using Save Instance State
Because onDestroy is not called if, for example, activity was recreated because of screen rotation.
From the Activity documentation:
The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
So you should call foo.start/foo.stop in onStart/onStop or onResume/onPause.
--
Update:
If I understand correctly, the problem is that you are tied to a singleton/monostate object Foo the should be unique for all objects, and must be destroyed when ALL activities are destroyed.
The problem is that nothing can guarantee that only one instance of activity has a runinng Foo, because onDestroy can be called after a new instance is created.
So the solution is to use an Instance counter:
public class Foo {
private int instCounter = 0;
public synchronized void start() {
...
++instCounter;
}
public synchronized void dispose() {
--instCounter;
if (instCounter == 0) {
// dispose
}
}
This should do the trick.

Use of onDestroy( ) in Android

If Java provides Garbage Collection, then what is the need of onDestroy() in Activity Lifecycle?
onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space.
Here is an example......
public void onDestroy() {
super.onDestroy();
}
OS decides when things "go away." The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed but it does not mean that the activity will, in fact, be GCed. Here is a good article that I recommend people to read that relates to creating an exit button. While it's not exactly what you asked about, the concepts will help you understand what's going on.
You can use onDestroy() to finalise the program. I have used it in the code bellow to tell the server that the client is closing its socket to the server so I can notify the user on the server end that the client has disconnected.
client:
...
protected void onDestroy(){
super.onDestroy();
if(connected) {
clientMessage.println("exit");
clientMessage.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
}
...
server:
...
while (connected) {
input = clientMessage.readLine();
if ("exit".equals(input)){
break;
}
...
}
...
onDestroy() is a method called by the framework when your activity is closing down. It is called to allow your activity to do any shut-down operations it may wish to do. The method doesn't really have anything to do with garbage collection (although your shut-down operations—if any—might involve releasing additional resources that can be gc'ed). In particular, it has nothing to do with C++ destuctors (despite its name).
If you have no shut-down operations to do, you don't need to override it. The base class does essentially nothing.
onDestroy may be called when an activity is destroyed, but you can not count on it. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
See: http://developer.android.com/reference/android/app/Activity.html#onDestroy()
In the Android Activity Lifecycle's onDestroy docs:
onDestroy() is called before the activity is destroyed. The system
invokes this callback either because:
the activity is finishing (due to the user completely dismissing the activity or due to finish() being called on the activity), or the
system is temporarily destroying the activity due to a configuration change (such as device rotation or multi-window mode)
The Activity#onDestroy() API docs also answers it quite well:
This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. source
As the quote from the docs say, its for preventing a destroyed activity leaving things around (e.g. memory leaks through referencing, threads), but only when the rest of the app still runs. If the application process ends, it doesn't matter if you forget to clean up threads or other resources since the OS will do it for you. You don't need to override onDestroy.
There is no need to do what sam786 is doing (overriding and just calling the super method) as that is absolutely useless. All other answers seem to go along the lines of "clean up", but don't explain what kind of clean-up or when. You should not be saving any data in onDestroy(), as you can't guarantee it will be called, so you will lose data sometimes. It won't be called when you press the home button, for example (the case where you want data to be saved).
The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed
Article Exit Button in Android
It gives your program a chance to do things like cleanup resources (say threads) so that they don't pollute the associated application. If you don't have any use for it, then don't override it.
See:onDestroy()-Android Reference

onDestroy, killing a running thread

I have a method like this in my class which extends Activity
#Override
public void onDestroy() {
Log.i("onDestory: ", "Inside OnDestory!");
bluetoothCommunicator.destroyedApp();
super.onDestroy();
}
The method destroyedApp() look like this:
public void destroyedApp() {
if(server != null)
server.destroy();
}
Where server is an Instance of a class which extends Thread
Here is the scenario:
I'm opening the application for the first time, inside my onCreate method, I create a new instance of the bluetooth class which sets up the BluetoothServerSocket, this works fine and I'm able to transfer files to my phone.
This also works when I have my application in the background, because the thread is still alive.
But
When I'm killing the application, according to the Activity Life Cycle
The onDestroy() method should be called by the Android Framework. And when I'm launching the application once more, the onCreate method should be called, but it doesnt seems that an instance of the BluetoothServerSocket is being created. I have no LogCat info, because the device which sends the bluetooth file, only says:
Error Log:
Write Error:
Transport endpoint is not connected
__obex_connect:
error=-2
Unable to connect to the server
Error
Which tells me that the BluetoothServerSocket is not "alive"
Any suggestion on how I can accomplish this?
There is generally no guarantee that the onDestroy() method will be called at all. According to the docs:
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
So I would first test if it is being called reliably.
Also, you are callling super.onStop() in your onDestroy(). It should be super.onDestroy()
Since I cannot comment, I am posting here.
As, commented by Egor I dont think you can call onStop() from within onDestroy(), Android will itself call onStop() following onPause() depending on the memory.
Now, note that stop(), suspend() and destroy() methods of thread are deprecated, the only safe way of terminating a thread is to have thread exit its run().
Now, when you are calling server.destroy(), there is a possibility that it still holds some link in the memory and therefore Garbage collector will not be able to garbage collect your activity. Hence, I believe this could be the possible reason why your onDestroy is not called.
Point me if I am worng.
How are you killing your application? I was looking for a solution for your problem in the Application class and I came across this information about the onTerminate() method:
This method is for use in emulated process environments. It will never be called on a production Android device, where processes are removed by simply killing them; no user code (including this callback) is executed when doing so.
I remember I had a similar problem in one of my apps, where some components' onDestroy() method was not called because I used the "Clear memory" button in the Task Manager (Samsung Galaxy 2)

Categories

Resources