Android: Window leaks on finish - android

I have read the other window leak posts and have tried what what suggested there to no avail.
I have 3 activities: A, B, and C. Activity A gathers information from the user. Activity B displays a spinning ProgressDialog while it communicates with a server on another thread. When the thread finishes, it dismisses the ProgressDialog and starts the next activity. Activity C displays the information from the server to the user. Activity B is set up so that when the user hits back from C, they fall back to A.
It is important that these tasks be in separate Activities.
As of now the app successfully does what it is supposed to in most cases, except in the following scenario: If the user changes the orientation while in activity C before returning to Activity A, the app crashes due to a window leak.
I am dismissing the ProgressDialog inthe onPause() of Activity B before istart C.
I have tried dismissing the
ProgressDialog on the main thread
using a handler as well as in the
separate thread.
When the user does not change the
orientation in C, no window leak
occurs.
Any ideas? TIA

This often happens where ProgressDialogs are used. I experimented with ProgressDialog a while back and found the thing to do was dismiss() it from onPause() and create it anew from onResume(). The background task obviously needs to survive your Activity & dialog so I used onRetainNonConfigurationInstance() to pass the task instance from the destroyed Activity to the new one.
An alternative, cheatier workaround might be to simply prevent your Activity from being destroyed and created anew merely because the screen orientation changed. Do this by adding android:configChanges="orientation" to the tag(s) in your AndroidManifest.xml.

I solved my problem by completely changing how i handled everything. I now have only two activities (A and B) and display the ProgessDialog in activity B while handling the savedInstanceState as needed in order to work around the problem.
Even though I have fixed the problem on my app, I still dont know why it was occuring before and would like to learn more about window leaks and why i was having problems. If anyone knows more about the problem i was having, please post as I'm sure there are others with the same problem.
Thanks

Not sure if this was related to your specific problem, but I had a similar issue which had to do with leaky windows for dialogs that are created in the onCreate method of an activity. So if your activity starts up showing a dialog, and you do a config change, the OS remembers which dialogs were shown, so when the activity is killed & restarted, the OS attempts to restore your old dialog while your activity tries to show the same dialog again (since it's in onCreate). I found by only showing the dialog during onCreate if it's not a config change (ie. savedInstanceState != null), the leaky window problem went away.

Related

Why is this happening? saveInstanceState=null

The above issue arises once in two debug. And the weird thing is app doesn't crashes, it stops responding.
What does this mean? And what wrong is happening inside?
You should really read the documentation on this, it will help you out a lot.
The savedInstanceState field is set when your Activity is being re-created from a previous instance. This happens e.g. when the device changes orientation or when the user navigates away, and then navigates back to your Activity. When the field is set, this allows you to restore the state of the Activity as the user left it.
The savedInstanceState field is null when your Activity has no previous state to restore from.
When your Activity is about to be destroyed, you can add variables to the savedInstanceState by overriding onSaveInstanceState(Bundle bundle) in your Activity, and adding them to the Bundle. The next time your Activity's onCreate(Bundle savedInstanceState) will be called, the fields you set in the onSaveInstanceState() will be available to you in the Bundle.
Finally, the "application not responsive' dialog is shown when you do too much work on your application's main (UI) Thread. However as pelotasplus mentioned this may also occur when you connect the debugger. If this dialog is shown when you have the debugger attached I wouldn't worry about it. However, if this dialog is shown during normal use of your app, this indicates you perform too much processing on the main Thread and you should move the heavy lifting to background threads, e.g. by using Loader, AsyncTask, IntentService, Thread or any of the other options available for this.
There are two things here, first of all
saveInstanceState = null
you see in your debugger is nothing unusual. Sometimes it's null, sometimes it's not. This is how Android framework works ;-)
For more information about that go read official docs about Activity lifecycle: https://developer.android.com/training/basics/activity-lifecycle/recreating.html#RestoreState
Second thing is that ANR (application not responding) window which happens a lot when debugging your apps. Just press WAIT and you are good to go.

Starting an Activity from Notification destroys Parent Activities

I have an app with 4 activities int the sequence say A->B->C->D and a service S that is started by A when the app is started. Now on a particular condition this service triggers a notification which again should start activity C withing my app and with the arguments that C usually needs from B. Also to function properly, C needs to use a static variable from the activity A. That was the setup.
Now what happens is when the notification is triggered from the service S and I click on it, activities A and B are automatically destroyed resulting in a force close(Since my activity C depends on a static variable in A). Why does this happen. I have used a TaskStackBuilder to place C's parent activity(i.e B) onto the stack so that normal back behavior takes me back to activity B.
Can anyone tell me the reason of this behavior. I do not want to run my Activity C as an interdependent task. I want it to be the same instance as that already in the app.
Please help me understand the problem here.
Activity should be independent. It is dangerous that activity C needs to use a static variable from the activity A. Although you create activities in order like A->B->C->D, Android may destroy A/B/C/D when your app is in background, and when user returns to your app, only activity D is recreated.
I encountered the same problem as you once, Starting an Activity from Notification destroys Parent Acitivities. This is because I used TaskStackBuilder. And even after I stop to use TaskStackBuilder, the problem remains. Only after I uninstall the app, it works as expected.
Check the comments for https://stackoverflow.com/a/28268331/1198666
This is happening because the Activity Lifecycle behaves differenty from ICS onwards. This fact answers this question, however I am yet to find out why this is happening. If someone wants to see the code and verify this behavior for themselves, HERE

Pausing/Resuming Activity outside of an activity

I have 2 activities. Main Activity A & Activity B
I do not want Activity A to destroy. I am starting Activity B in a new task.
public static void startActivity(Class<?> startClass) {
Intent intent = new Intent(Constants.getActivity(), startClass);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Constants.getActivity().startActivity(intent);
}`
Constants.getActivity() returns the Context on current activity
startClass is the either activity "A" or activity "B"
Thing is they create/destroy the activities and they leak. Am I doing it wrong? How can I start activity "B" from activity "A" and vice versa keep them both in background when I dont need them.
First of all, what are you trying to do? You should always separate things you want to do in the background from your UI. Think of your Activities are simply a container to show the UI, everything else can be stored and restored from persistent storage or savedinstance bundles.
It is very crucial that you understand the difference between Activity lifecycle and Service lifecycle here.
I'm going to refer to my answer from another question here:
Your app will be in the background, onResume and onPause will both be called, provided that the OS have enough memory to keep the new app and all the old apps.
If you have a long running process that you need while the user not looking at it, use a service.
If you need the user to return the app in the same state, you need to do the work in onResume and onPause to save the state information and initialize your UI again when the user comes back. If you are really worried that it can get killed (well, it shouldn't lose the bundle I think), you can store them in SharePreferences for your app.
If you want to know when the app returns from that specific share intent, use startActivityForResult
You cannot keep an activity "alive" as you said. When an activity is paused, Android system is always able to claim its memory and unload it, at any time.
But if you want to switch from A to B, then maybe A and B can be different views inside a single activity. Maybe you'll want to have a look at http://developer.android.com/reference/android/widget/ViewFlipper.html
When you use tasks, cleanup is very important. You need to cleanup all tasks in the activity. readthis
If the activity does not have a lot of crazy initialization, just use finish and onCreates. Else be aware that onResume will be called often as you switch between activity's. Cleanup will be crucial here. If you dont cleanup, its possible one of your activities (with dead object reference from the other cleaned up activity) may come back up from the activity stack and throw exceptions. Its very difficult to debug this kinda exception.

Changes to SQLite database lifecycle between Gingerbread and ICS; intermittent null pointer exception

I noticed that after I upgraded to ICS from Gingerbread my app started crashing in circumstances when it had worked satisfactorily under Gingerbread.
The app's main activity (activity A) has a menu option which opens a ListActivity (activity B) populated from a database; when an entry in the list is clicked a third activity (activity C) is opened. When activity C is closed with the Back button activity B is supposed to be redisplayed.
In Gingerbread (and earlier Android versions) this worked fine, and continued to work OK in ICS most of the time. However, it crashed if I navigated away from the app leaving activity C open for an extended period. On returning to the app and trying to back out of activity C to activity B the app would stop. LogCat reported "unable to resume activity" because of a null pointer exception in onResume in activity B.
The offending line in the onResume method contains a reference to a DBAdapter which is defined in the onCreate method of activity A. By logging calls to activity B's various lifecycle methods I found that activity B is always (as expected) stopped when activity C is opened. Provided it is only stopped there is no problem: the DBAdapter must still be defined when onResume is called. However, if the app is left for a longer period activity B is destroyed and in these circumstances the DBAdapter (defined in the onCreate method of activity A) must also become undefined.
A fix for this problem seems to be to insert if (Global.mDBAdapter== null) {Global.mDBAdapter = new DBAdapter( this, "DatabaseName" );} into the onCreate method of activity B.
I would like to check that I have understood this correctly. Is there documentation that describes the change (between Gingerbread and ICS) in lifecycle behaviour of a SQLite database adapters/helpers?
It seems you were making assumptions that weren't warranted, and you just happened to be getting away with them on your Gingerbread device.
An Activity's process is always killable any time after onStop() has been called, so at the end of onStop(), you must be prepared for your next lifecycle callback to be any of these three:
onRestart() -- If the process isn't killed and the Activity is restarted before long.
onDestroy() -- If the system has decided to stop the activity and finds it convenient to let you know.
onCreate() -- If the process was killed without calling onDestroy().
(Pre-Honeycomb, the process is even killable after onPause().)
So what it sounds like is happening is that when you've navigated away from Activity C for a long period, the whole process is killed. When you go back to Activity C, then press BACK, Activity B goes through onCreate() -> onStart() -> onResume(), and you seem to be assuming you have global state set up by Activity A, which isn't the case.
This wasn't a change between Gingerbread and ICS; you were just getting lucky before.
Good resources to read and understand:
The Developer Guide article on Activities
The documentation for Activity
Update: You asked in the comments below what exactly Android retains about your application state when it is destroyed. My impression is that it is basically just the Activity stack and any Bundles from onSaveInstanceState(). (It doesn't specifically remember which Activity was open, that's just the top of the stack.) That makes sense: Android handles its end of things (the Activity stack) and you handle yours (by saving what's most important and being prepared to recreate the rest).
The default implementation of onSaveInstanceState() calls the method of the same name on all of your Views, which can make it seem like you're getting some data saved and restored for free. Without overriding that method, however, you certainly won't have any of your own data members saved, static or otherwise. That makes a lot of sense to me: automatically doing so would require reflection and would be inefficient, often wasteful, and quite confusing. It's up to you to save what's important to be saved, and Android gives you the callbacks to make this easy.
Here's another resource for you:
Recreating an Activity
You don't necessarily need to deal with onSaveInstanceState(), however; some things make much more sense to be recreated, e.g. your database adapter.

App partially closing

I'm building an application using a service and the fragment compatibility pack and am running into some weird behavior. I have a FragmentActivity and a ListFragment which implements LoaderCallbacks, and when the FragmentActivity starts it kicks off a service to download data and fill in a database.
Suppose I'm on that screen, and I navigate past it by clicking on one of the rows of the ListFragment. If I then hit a nullpointer, or any other exception that causes the regular force close dialog to pop up, I hit the force close button on the dialog and the activity I'm on does indeed get shut down, but I end up back on the FragmentActivity screen, rather than say my Android/launcher home screen.
To me this says that the app is crashing but somehow the fragment activity is getting restarted. The behavior occurs if I hit the red stop button in the debug view in eclipse - the current activity gets killed but that damn fragment activity is still there.
Obviously I don't want my app to ever get a force close dialog, but really what I'm trying to figure out is if this is a symptom of me not coding something correctly. Currently I never stop the service, mostly because it gets reused over and over again throughout the app and I haven't gotten around to coding up a way to close the service safely without prematurely ending a new request to it.
Is the service keeping a reference to the Activity via the ListFragment and LoaderCallback or something? Why is this FragmentActivity seemingly invincible?
This is happening because your process is killed, but there are other activities on the activity stack. This is the expected behavior, as the system attempts to start a new process on the next activity on the stack once your offending activity was removed. See here and here.
If you want to remove all of your activities off the stack after a force close, one thing you can do is hit the back button until you are taken to the home screen. Unless you override the behavior of the back button in your app, it destroys your current activity and takes you to the previous activity. Once there are no more activities left, you will be taken to the home screen and can start your app again from eclipse, and it will start you off at your main activity.
i had run into similar problems, with Databse loading and Nullpointer Exceptions. I don't know your special case but it might help to separate the Databse out into a Content Provider if you aren't already doing that, that way you are decoupling the Fragments form the Database more, it might help with the errors.

Categories

Resources