Avoiding IllegalStateException “Can not perform this action after onSaveInstanceState" - android

This topic has so many different SO questions linked to it, I know, but I think most people ask their questions while still confused about why things happen when.
I've read Alex Lockwood's article on Fragment Transactions & Activity State Loss, and although he provides clear arguments for all things (read the article - it's really informative and easy to understand), he doesn't provide a full proof work around for my situation - using AsyncTasks.
Here's what we do in our app:
User presses a button which initiates an AsycTask doing a call to our server.
A phone call is initiated from within the app using Intent.ACTION_CALL.
Phone call is ended and user returns to the app.
AsyncTask responds with server call response.
App code processes the response and displays output to user.
So obviously, when the user goes to the phone call, our app is stopped. So when the AsyncTask gets to onPostExecute() and provides the server call response, we might not be in a live activity, and it's probably after onSaveInstanceState() has been called.
So how do I solve this?
I have to communicate the results of the server call response to the user through an AlertDialogFragment, but when I want to show that alert, I get IllegalStateException.
Alex Lockwood suggests that I make sure that no fragment transactions occur after onSaveInstanceSate() has been called - i.e. (I figure) don't trigger anything in the app (like displaying an alert), from the onPostExecute() of an AsycTask.
So when then?
Should I do something in onResume() like check there whether I've received a response from that AsyncTask server call, which I should probably save to shared prefs rather than process and present results to the user, and if so, display that alert to the user?
Please advise?

An AsyncTask will still run after an Activity is navigated away from. This means that onPostExecute() may be called when an Activity is no longer visible and any UI changes that should be done in onPostExecute() will result in an Exception, most likely a NullPointerException or an IllegalStateException.
To remedy this, you will have to either manage the AsyncTask yourself by stopping it in your activity's onPause() and restarting it in your activity's onResume() or place the task in a retained non-UI Fragment. In my opinion, these solutions are a little hacky. I would highly recommend using an AsyncTaskLoader in place of an AsyncTask when the UI will be modified after the task executes. AsyncTaskLoaders use a LoaderManager which handles the Activity/Fragment lifecycle for you.
There are many resources that demonstrate the correct implementation of AsyncTaskLoaders, I have listed some of them below:
Android developer documentation
Alex Lockwood's blog post
Wolfram Rittmeyer's blog post
I used the AsyncTaskLoader class in one of my open source applications, CrimeTalk Reader, to load web data using Jsoup and put the resuts in a ListView. The class that uses it can be found on Github.
In instances where you want to run a long-running task without UI interaction, you may want to check out the IntentService class.

Related

Is there any point in using Asynctasks for api calls that require a response to proceed?

I feel that the answer to this question is too obvious, but part of me still wants to ask it anyway.
I am creating an Android app that makes several HTTP POST/GET requests using APIs when the app is launched for the first time by the user. All these requests are made by launching Asynctasks within the activity.
For example, there is an activity where athe user has to select an item from a list retrieved from the API. After he selects one, a progress bar is displayed to the user while the app sends the selection to the API to retrieve another list, and in the next activity, the user selects items from this list. Clearly, the user can't go this second list until a response has been received from the server after the app sends it the first list's selection.
In such a case, is there any point in using an Asynctask to send the selection of the first list, since the user is prevented from doing anything (by being shown a progress bar) until a response is received and the next activity is started. Wouldn't it make the code less complex if I just made the API call on the main thread?
I hope this wasn't too confusing.
Thanks
I got your doubt completely. Good question. The root cause of the doubt because you are thinking you don't need to interact with the app till the process completes. But you actually want to. Event the progress bar will freeze if you could do something like it.
Ok, let's just assume you don't even have a ProgressBar. However, handling the different UI components such as Spinners, EditTexts is not the only duty of the main thread. It should define different callbacks in the activity lifecycle. Doing big tasks in main thread will also freeze callbacks like onPause(), onStop() etc. That is why the 'NetworkOnMainThreadException' is being thew.
Basically you cannot call the api on main thread as it will block the UI. Also now Android does not allow it to happen and throws 'NetworkOnMainThread Exception'. Its fine to use Asynctask for any task that takes few seconds and you get the callback in it , which in your case is required before you proceed to next screen.
Best way to do it is by using Networking libraries:
Refer this
https://developer.android.com/training/volley/simple.html
First of all you cannot do netwok call on main thread, it will raise NetworkOnMainThreadException , You can still by pass this exception by adding the couple of following lines in your activity
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
but it is always recommended to perform network operation in background,
else it may cause your app to stop responding, and can result in the OS killing your app for being badly behaved , go through this article once link
Any operation that takes more than a few seconds to perform should be added in a separate thread. All network operations should be performed on AsyncTask or do have a look at RxJava and RxAndroid. To be specific to your operation, any UI Operations during a network call can be performed in onPostExecute. If you're working with thread class then use a Handler.
As others mentioned, if main thread is used for network operation, it would make your app unresponsive.
User may want to start a different flow in your app by starting an activity from menu or action bar whatever is available in your app to start other flow.

How to decide whether to use ASyncTask or not in android?

I have a simple Android UI. When user clicks Button, it takes the user's location and then it goes to 4-5 websites and gets all the events in that hour. Then, according to the user's location, it compares the closest ones, and according to a radius given, it shows the event names in a new screen.
After clicking Button, it will go into another screen and will write something like searching for location or progress dialog, or location identified. After that, it'll show the events to the user. So, should I create 3 activities and 3 screens?
According to this link
how to use method in AsyncTask in android?
He says don't prefer AsyncTask for long network jobs.
I can't use location methods inside AsyncTask. Before executing I should send location as parameter. But again, computeDistance method needed. At post execute method, I can post events to new UI.
But when the user clicks these events, from onClick I can do jobs but I can't find or retrieve info of these events.
I decided to use AsyncTask after commenting somewhere here and someone answered me to use but I can't find that post.
And now i am unsure about to use or not.
I need webconnections, so I don't want to make them in main. So it is good to use AsyncTask for that but is it necessary?
This is what I would recommend:
Use AsyncTask. It will run a background thread and give you a way to display progress in the UI thread as each website is checked. This isn't a "long network job" compared to, say, streaming a video. IMHO, using a Service for something like your operation is just too heavyweight. So start out with an AsyncTask.
Once you have that, however, you will discover your next problem, which is that your web operation might take long enough that if you rotate the device, the Activity will be torn down and recreated in the new orientation. Then when your AsyncTask completes, the Activity it was supposed to call back to is no longer there. Oops, now your user doesn't get their results.
The best solution I have found for that is to use a special fragment to "host" the AsyncTask. This fragment will not create a view and use setRetainInstance(true) to keep the fragment alive during Activity re-creation.
You can read about this novel technique here: Handling Configuration Changes with Fragments
AsyncTask is an abstract class provided by Android which helps us to use the UI thread properly. This class allows us to perform long/background operations and show its result on the UI thread without having to manipulate threads.
Android implements single thread model and whenever an android application is launched, a thread is created. Assuming we are doing network operation on a button click in our application. On button click a request would be made to the server and response will be awaited. Due to single thread model of android, till the time response is awaited our screen is non-responsive. So we should avoid performing long running operations on the UI thread. This includes file and network access.

Using AsyncTask to preload data for a new Activity

I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!
Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.
Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.
I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.

Which should I use Handler, AsyncTask or Thread?

This may be a common question but I couldn't find my exact scenario. I understand that its down to developer choice in a lot of ways but I don't know enough to choose best.
I have my initial app splash screen which will just display a logo whilst checking the user is logged in. If their login details are already stored in a sharedPreference then I want to check those details against my online database of details for verification. Once this is all checked I'll either pass the user through to the main app screen or a registration screen.
So when doing this check of user details, and then verifying them. Should I do this in a separate or use a handler? I don't think AsyncTask is needed as I'm not wanting to pass any progress details back to the UI?
TIA
I suggest using AsyncTask.
First of all, because AsyncTask is a complete threading framework (that uses Thread and Handlers behind the scenes) that allows for a nicer control of single thread operations. Including cancel() for example, in case the user decices to leave the application before the splash screen is done.
I don't think AsyncTask is needed as I'm not wanting to pass any
progress details back to the UI?
actually, yes you do, even to start the new activity (either Login or AlreadyLoggedIn) you have to call startActivity() from the UI thread
You should probably do this in a separate thread because it is network activity. IntentService is a good option. I think your main concern is that whatever method you choose needs to work even if the user rotates the screen and the activity is destroyed and recreated.
Maybe use a Fragment for the splash screen with setRetainInstance(true), so it will get reattached to the activity after configuration change. Then you can either pass the service a Handler (or a Messenger to be more accurate), or have the service send out a broadcast intent when it finishes working.
When to use an Async Task?
AsyncTask helps in offloading memory intensive/blocking call to a background thread while, your UI operations can still carry on in the UI thread.
If any operation blocks the UI thread for more than 4-5secs, you might also get an ANR(Android Not Responding) dialog. AsyncTask come handy when you want to update the UI after doing the process (onPostExecute) and also before starting it (onPreExecute).
Using a Thread
Whatever you do in doInBackground using an AsyncTask can also be achieved using a Thread. But incase you need to do any UI operation you will need to use a Handler or runOnUiThread to accomplish your task. Refer to Painless Threading in android in case you wish to use threads.
Also what Budius said is true.
In your case you can use an AsyncTask to check for user creds in sharedPref and then appropriately authenticate with your middleware and finally in onPostExecute navigate to a new activity.
In the meanwhile you can show a progress bar to the user signifying the on going auth process.
To add on to that. I had a very similar situation where I had to verfiy a users login (which was stored in the phone) in the background from a "home screen". I used the IntentService ResultReceiver pattern. At first it took a bit for me to get up-to-speed on it, but once its implemented its very simple to manage.
Basically, you start the activity that is your intent service, passing it any parameters that are needed (username, password, etc...). In my case it was a separate class that used REST to verify the user. Once the REST class has done its work, the ResultReceiver method onReceiveResult, returns back the data to the UI activity from the REST activity.

Android app architecture - where to put REST API call code?

I want to better understand how to structure an Android app where an activity fires off an API call (for example).
I'd currently implement it by putting the API call into an AsyncTask subclass, passing it a reference to the activity so it can update the UI in onPostExecute. But my gut-feel is that this is creating overly-coupled code.
I'm wondering whether instead I should put an API call like that into a service, and use a BroadcastReceiver to update the activity.
What say you, AsyncTask, or BroadcastReceiver?
I usually follow the Local Service pattern. I have a strong suspicion that this is how the official Twitter app works and that this is the pattern most of the Google apps use. This also solves the issue of your app going away (getting killed or going into the background) before the task finishes, or if the phone switches configuration during a background task.
BroadcastReceiver and service is an overhead here. A request to web-service should not go to long. Service is appropriate in case of downloading files or something similar.
AsyncTask way is the right one here. But I would suggest you showing a progress dialog to let user know that your application isn't freezed, but doing some useful work.
See the example here.
AsyncTask is just fine. Only thing you should worry about is referencing you Activity using WeakReference to avoid whole Activity be memory leaked. It isn't overly-coupled code imo if you using observer or events patterns.
I would go with a service only if the call is going to take long, so that the user can leave the app while it's completing.
I'd use the AsyncTask if the task is short enough that it almost wouldn't go ANR if done in UI thread.
(disclaimer: I consider myself a beginner, and I'm expecting comments from more experienced people)

Categories

Resources