startActivityForResult workflow - android

I'm using an Activity A which starts another Activity B to get a result (the id of a customer), all seems to work perfectly but I have few error reports which tend to indicate that I have a concurrency bug between the UI building process and the onActivityResult method.
The whole hypothesis is based on the fact that the Activity A could have been destroyed during the appearance of the Activity B and created again which can create problems because Activity A creates its UI by doing some asynchronous network requests.
Of course, I'm not able to reproduce the bug (stopping the activity manually would be the nearest reproduction but only if the problem is the concurrence bug I mentioned).
So, in short,
Is it possible that an activity starting another one for result is cut by the OS while the user is in the newly created activity? (and then recreated when the user is finished and when setResult and finish are called on the newly created activity).
-- Update --
Sorry for the imprecision, Activity A is containing a Fragment which is starting the Activity and doing the network stuff, so it's maybe a matter of fragment (so the question is also "could the OS cut a Fragment which started an activity for result?").

Related

Delaying activity start

When a user enters an activity on my app I want to perform some logic during onStart and possibly launch a second activity before letting the user see the first activity (think of this as a pin protected activity)
I have a small issue where the contents of the first activity are shown for a second before the second activity is started. This happens when the user uses the home button to get out and in to the app. Is there a way to prevent the first activity to be visible at all before performing the logic validation?
This is more of a "design" solution to your problem and not clear if it'll work for you. I had something similar in the app I'm working on. What I did instead, was to create an interstitial Activity that resembled the same starting state (i.e. not yet completely loaded) of the Activity (Pin-protected Activity in your case) that is about to be started. Once I'd made my appropriate decision about whether or not I could go on, I just navigated to that initial Activity. In your case, I could see you making the decision on this interstitial Activity, and then navigating to the Pin-protected Activity or to the other one if conditions were not met properly.
The only downside to this approach is that the app does a quick flash with the additional Activity, but I think the increased separation of logic is worth it.

ANR while trying to load Activity after FragmentDialogDismiss

I have an activity that sends a BC and waits 5 seconds for the response using AlarmManager.
Once i get the broadcast i:
1. remove the FragmentDialog using mDialog.dismiss();
2. start a new activity using getActivity().startActivity(myIntent);
I'm inside a Fragment (using TabFragment from the support library and MyTabActivity which i created).
The thing is i constantly getting balck screen and ANR, if i remove the line startActivity()
I'm not getting the ANR, the fragment does gets dismissed, but my activity doesn't show, i get the black screen and if i press it, ANR.
What i thought about is that the fragment manager started out working on the activity and then i started a new one that fucks up android, since i'm basing myself on fragment i really don't know how to get out of this mess, thought of using handler in the activity to post my activity start in 300 millis, this is a very very ugly solution.
Any nice ideas ?
the problem seems to be that i unbding a service twice in onStop of the activity due to the fact that once i call unbind ServiceDisconnected is NOT called and changes the state of my activity to unbonded (state i follow).
since onStop is never eding the original activity gets the UIthrehad and make the whole app stuck...

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

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.

Updating Activity UI from Different Activity Method?

I have a tab widget where one of the tabs is a chat-type feature. I want to update the chat data at an interval (variable depending on whether the chat tab is active or not).
The best approach seemed to be using an AsyncTask in my main TabActivity class, as that would avoid any issues of the chat activity being destroyed while in the background, while an AsyncTask was running. I wanted to ensure that the Activity isn't destroyed and recreated, thus causing my AsyncTask to be unable to modify the actual active Activity's data.
However, now that my AsyncTask is in the TabActivity activity, I don't have a direct way to call my Chat's ListAdapter notifyDataSetChanged() from my onPostExecute() method anymore. Is there a way to get a reference to a given Tab's current Activity from the TabHost/TabActivity?
Or, alternatively, can I assume my chat activity will never be destroyed as a child activity of the TabActivity activity (well, never destroyed while the TabActivity is active at least), and then just put the AsyncTask in the Chat Activity?
Really the best way to do this is to have a thread that runs and periodically gets the chat data. Then from your UI you can poll the thread to get new messages. This way you can have the thread running no matter what happens to the Activity.
If you're using the Intent loading mechanism for your tabhost, then you should be safe in assuming the task won't get randomly killed any more than the TabHost itself (only paused), and you can safely modify views in it (as safely as you could from the TabHost, at least).
But beware: Any activity can be killed at any time (example: if a user clicks on a link in the tab that opens a new activity while your task is still running), including the tabhost itself, which can lead to ugly crashes when the task returns and tries to update the UI of the now-dead Activity. So make sure to either cancel your AsyncTasks on destroy, have the asynctasks check that your activity is still active before returning results (see WeakAsyncTask in the Android source tree), or use an Activity-independent (semi)persistent pollable background-thread solution like CaseyB suggests (cwac-bus is a nice premade solution in that vein).
Alternatively you could just have the AsyncTask's UI-updating code catch all exceptions (I've seen a few apps that do this) and fail silently, but that smells funny to me.
Lately I've used a modified version of the WeakAsyncTask in most places that checks that the activity is non-finished on returning, personally.

Categories

Resources