Starting an Activity from Notification destroys Parent Activities - android

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

Related

Android application's initial activity is not the launcher designated activity when re-entering the app with the back button

I ran into a similar issue with the recent list in that there seem to a handful of conditions where an app will be completely destroyed but some other process will launch the app cold from the last activity that was being used. Since my app has a state that is built up over several designated activities I need to prevent this (i.e. null refs from onCreate()).
Without checking for state is all my onCreate() functions is there a way to just prevent this?
Also, other than the launcher, recents, the back button from other apps - are there more conditions where another thing can launch my app if I have not giving manifest permission to launch it explicitly with an intent?
Thanks!
If I understand this correctly, you have initializations in activity B that rely on activity A having passed them in. If an intent launches activity B first, without it being active, or being launched by A first, your activity will crash.
Easiest solution I can come up with is make your activity A (I assume your main activity) the broadcast listener for all the intents you wish to handle, and based off the intent action, dispatch to the appropriate child activities (B, C, whatever). That way activity A does all your initialization, and you can still launch into the appropriate activity to handle the original intent you wanted to.
Alternatively. If you detect your children activities are in an invalid state, you could put initialization into a parent activity that all your activities extend from. That way you should be able to initialize properly if the activity is a fresh launch. I'm not really a fan of this, I prefer making sure my activities are dependency injected with appropriate data.

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.

How do I start two activities at same time?

I want to start two activities A and B. I want A to be in the foreground and I want B to be in the background.
At some point, I want to switch the order of the two Activities: A is moved to the background and B is moved to the foreground.
But here there are three different activities comes live, Acitivity A will start actvity B in bacground and activity C in foreground
You can use below link to start one of your activity in background
Sending Activity to background without finishing
Other activity which you want to start in foreground can be started normally.
You don't really want to do this. Activities in Android are meant to be shown to a user and be interacted with. If you launch more than one Activity, there is no guarantee that your other Activity will even be around when you need to display it.
Perhaps it would help to know more about what you are trying to accomplish.
If you want to have code running in the background, you should consider writing a Service or an AsyncTask.
Service: http://developer.android.com/guide/topics/fundamentals/services.html
AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html
Your question is not clear, if you are asking whether or not you can start two activities at the same time? The answer is no, Android's mechanism is such that an activity can start another activity and so forth.
Read this for more reference on how you can start and use activities.
http://developer.android.com/guide/topics/fundamentals/activities.html
Moreover read this to understand how you can switch between your activities to get the desired result http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html
There are 2 ways to do what you want:
The first way is to launch one of the activities (the one you want "in the background") and have that Activity launch the other one (the one you want "in the foreground") immediately (in onCreate(). When the top Activity is finished, the other one (the "background" Activity) will be shown.
The second way to do this is to simply launch the Activity that you want to be in the "foreground". In this Activity you can override onBackPressed() to launch the other ("background") Activity. In this way, the user experience is as you desire, but you don't need to launch the "background" Activity until it needs to be shown to the user. Depending on your requirements, you can also switch back and forth between these 2 activities, by simply calling startActivity() with an Intent where you have set Intent.FLAG_ACTIVITY_REORDER_TO_FRONT when you want to move from one Activity to another. In this case, Android will bring an existing instance of the target Activity to the front of the task (if it exists) or will launch a new instance of the target Activity (if one does not already exist).
However, none of your terminology is correct and that causes problems when communicating with other developers. An Activity isn't in the "foreground" or the "background". These terms are used when talking about tasks. A task is in the "foreground" when the user is interacting with it and it is shown on screen. Other tasks are in the "background". A task is made up of one (or more) activities, and they are stacked in such a way that the top-most Activity is the one that the user is interacting with. The other activities in the task are not "in the background", they are just paused.

Task Killer not resetting stack

My application has a main Activity A and that does a StartActivity on Activity B. If somebody uses a Task Killer (e.g., Advanced Task Killer), the application is killed but when they run the app again I see the Application object is being built (onCreate called) and then it goes right into Activity B not Activity A. The Manifest has A being the Launcher Activity.
I also see the scenario if I run A, then Activity B, bring down notification list and run Task Killer to kill my app, and press the Back key, it creates the Application object and then Activity B object.
Any ideas on how to prevent this behavior? Activity B assumes that Activity A has already run. I am able to kludge this but have a boolean in the Application object which is set on Activity A. In Activity B onCreate, if that global flag is not set, I do a finish(). Must be a better way to handle this since I have quite a few activities that would experience the same behavior.
Activity B should almost never assume any other Activity has run. Activities are meant to be stand alone units. If B must depend on A then there should be some test for a precondition and if it fails, opens ActivityA via an Intent.
Instead of keeping the flag in Application you may persist it in SharedPreferences - then your Activity B will always know the correct value of the flag.

Categories

Resources