App crashes when user changes fragment during AsyncTask - android

I've got the following problem. In my app I'm loading data in an AsyncTask. The problem is, when the user now clicks on the icon to open the Navigation Drawer and opens up another fragment the app crashes. When the AsyncTask is finished the app doesn't crash. The problem that is encountering is, that when I switch the fragment (The fragments are always the same, just with another content dependent on the NavigationDrawer Item click) the app crashes.
I guess the problem is, that the async task isn't finished, I'm calling the same fragment again want to display different data.
So what would be my approach to handle this? Use for every different view a different fragment? I thought using the same fragment every time is much easier, since it's just displaying different data but the structure, layout etc. is all the same. Just the data that it gets is different.
I also thought about somehow "blocking" the user from doing any other actions while the asynctask but still show him that the app is processing. But that would be not the definition of an AsyncTask.
How would you approach it? Use different fragments for every different display? Or how? Block somehow? If a user clicks on an item of the navigation drawer the asynctask needs to stop all its actions (if some are done) and then restart doing all the actions. Is there a way to do it?
Please note that the fragment where the async is executed and the activity where the fragments are called are in two different files

You can either block the screen with a loading screen (not that good UX wise...) or you could cancel the asynctask when you change the fragment, in the destroy or detach method.
You didnt show the errors, but I would guess that the app crashes because you are trying to acess something in the asynctask onPostExecute method and it is no longer available...

I guess that it crashes because your AsyncTask is sending data to a class instance that doens't exist.You should change the Class that receives callbacks from asynctask. Anyway i can't give you a better answer till i will see your real code of AsyncTask ( at least onPostExecute() and onProgressUpdate())

use intent service to do that ask task means call ask task in a intent service that one is capable to handle background task without hang UI

Related

How to correctly manage ASynkTaks in Tabs which have the same fragment class

I have a FragmentActivity with 7 tabs, and all of them refers to the same fragment, the only difference is a parameter, that makes them to load throught an ASyncTask the data to show from a PHP that returns a JSON. My problem is that when I swipe from one tab to another, if the task from the first tab is still loading, it loads in the new tab, or crash, or doesnt do anything. However, the activity load two tabs, so the task is launched twice and is the same problem. Any idea?
While AsyncTasks are wonderful to have, they are intended to be procedures that are independent of any UI (e.g. saving information). For the longest time I was in the same boat and used AsyncTasks for work that would end up changing the UI (since hey, they have an onPost method).
What you should be using for any work that will affect the UI is called a Loader which will pay attention to the UI state of the Fragment. In your case the AsyncTask is probably attempting to access a UI element that no longer exists (View Pagers only keep the previous, current, and next views in memory). The Loader will pay attention to this and not attempt to change the UI.
There are plenty of examples out on the web, but in short you will need to create (extend) a Loader for each of your AsyncTasks (I recommend AsyncTaskLoader, if you do pay attention to forceLoad) and add the callbacks (LoaderManager.LoaderCallbacks) to your Fragment. Then when you are ready to load call getLoaderManager().restartLoader(LOADER_ID, bundle_args, loader_callback);
Keep a reference of your AsyncTask. I assume you have a callback which let's you know when the tabs have changed. When you get notified that tabs have changed you can check if your AsyncTask is null or not finished yet, if it isn't you call it's cancel() method.
if(asyncTask!=null && asyncTask.getStatus()!=AsyncTask.Status.FINISHED) {
asyncTask.cancel(false);
asyncTask = null;
}

Is using runOnUiThread inside AsyncTask inefficient and bad?

I know it sounds crazy that someone is using runOnUiThread inside AsyncTask. Somehow, it is working for me but I wanna know if it is an acceptable and robust approach or not. Here is the scenario:
I have an app in which after successful login, user is rendered to next screen. In this new screen, 3 different methods are loading different types of data from a web server. These methods are:
getMembersForList() : It loads the list of community members and shows it in a listview.
getProfileData() : It loads the profile of logged in user and shows his name , image etc on the screen.
getNotificationCounts : It loads the count of new notifications for the user.
I applied 3 different approaches for it :
(1) Calling all 3 methods simply in onCreate i.e. no exclusive thread is being used for any of the methods . In this case , the transition from login screen to this screen becomes very slow and black screen shows up for some time before this activity shows up.
(2) Calling getMembersForList() on UI thread and the other 2 methods on exclusive threads. In this case transition becomes fast and list shows up quickly but Notification counts and username etc. don't show up because WrongThreadException occurs saying that this thread can't touch other thread's views (TextViews for username, notification count etc. which are declared globally) . The same thing happens when I start these threads from an AsyncTask as well.
(3) Calling getMembersForList() on UI thread and then starting an AsyncTask in which the other 2 methods are being called in "runOnUiThread" inside doInBackground() method. This solves both the above issues. Now the screen transition is faster and the WrongThread exception is also not occuring.
So far the approach-(3) is working good for me but I am not sure if this is the right way to do it because runOnUiThread and AsyncTask are 2 completely opposite things. Can anyone please clear my doubts about this scenario. Thanx in advance.
Yes, use-cases like this are a big reason why the runOnUiThread() method exists in the first place. The idea is you allow your background thread(s)/AsyncTask instance(s) to run your lengthy operations in the background, and then provide a simple hook that they can use to update the interface when they have the result (or at arbitrary intervals, as different pieces of the result become available).
As long as that's what you're doing, then your usage is fine. What you want to avoid doing is performing a lengthy operation on the main thread, either directly or indirectly by passing in some lengthy operation from a background thread.
Of course you don't have to do it that way if you don't want to. You could use postExecute() instead. Or you could store the result somewhere and then use any sort of message-passing API to notify the main thread that the result is ready, and so on.
I would advice to run all the 3 calls in the asyncTask, and update the UI in the postExecute() of the AsyncTask after the background taks is complete, postExecute runs on UIthread so you need not call anything explicit to run them on UIthread.

Display loading screen using AsyncTask with ListActivity

I've got an app that uses ListActivity to give users a list of actions. When they click one I use an Intent to launch a separate activity.
My problem is that the actions that the app performs take about 20 seconds to finish, and since I don't want the user to receive that nasty ANR dialog, I tried to use AsyncTask to present them with a loading screen in the mean time. I tried using setContentView(R.layout.loading); on onPreExecute(), but it throws a NullPointerException which as far as I have figured out is due to the fact that loading.xml is not "a ListView whose ID is android.R.id.list".
So what can I do now? How can I show that loading screen? Is there a way around this pretty annoying situation? Any help would be greatly appreciated. Thanks!
I am not sure exactly what your use case is; you have a list of items that are populated immediately, and upon selecting one an action is taken? The action that is taken is to launch another Activity which performs background processing?
Or does it take that long to populate the list of actions?
If the former, you can use an AsyncTask for the long-running activity instead of an Intent to launch another Activity: in the callback you get for the click on the item in question, you would create the AsyncTask, and in doInBackground you would perform the long-running activity, with onPostExecute refreshing or manipulating your list as necessary.
Another thing to consider is using a dialog box to show a loading screen, if the loading is required to happen before you launch a new Activity.
If you can further describe your use case, I can help you more.
It's not the loading screen you need to have on the AsyncTask, it's that 20-second Activity initialization. I would look for a way to do all the setup in a background thread in a Service while the user is free to merrily bop around in other Activities. I'd try hard to find a way not to just stall the user for 20 seconds. Maybe take them to the target Activity and show them data cached from their last visit until the new set is ready.
Fire up and display your loading dialogs in your onCreate() of the Activity being called, then call Dialog.dismiss() in your AsyncTask's onPostExecute().

Handling of server requests and device rotations

I read a lot about handling rotation in android applications, but I still have so many questions and need to much to understand.
Let me explain my problem or implementation, that I'm using now in my application.
If an activity will be opened, a get request will be sent to server. This request will be executed in a Thread (new Thread(...)) and if request was completed, activity's ui will be refreshed.
But what should I do, if the user rotate his device?
By default, the activity will be destroyed and request will be started again and start a new thread, but the thread of destroyed activity may be still running.
I guess, it's a quite wrong way, I have now.
But what is the best approach, to handle this?
Probably is the best way to forbid rotation, but what If I don't want that?!
May be it's the second part of my question:
I saw a video form Google IO. Mr. Dobjanschi suggested to use services and to store retrieved data in content provider. So, probably I can use a service for executing my requests. But should data be replaced every time the get request was completed?!
Well dont know exactly how its done, You can try saving the instance and retrieving the same when config changes with following methods:
I have read about them but haven't really implemented them yet. I hope it can give you some start.
#Override
public Object onRetainNonConfigurationInstance() {
return(myServerThread);
}
private void restoreServerFunctions() {
if (getLastNonConfigurationInstance()!=null) {
myServerThread=(Thread)getLastNonConfigurationInstance();
}
}
You can specify that the activity handles the rotation itself. This is done through adding:
android:configChanges="keyboardHidden|orientation"
in the tag of the activity inside your android manifest. You don't have to actually handle the rotation but this will tell android to not destroy your activity. The base activity class will handle all the rotating of the user interface for you and your thread will be executed correct.
A small side note: if you are doing only a small server task use AsyncTask to execute the call to the server in the background instead of creating a thread. This will minimze some of the programming effort you need to communicate the results from the thread to the activity and update your UI.
One easy way, though I've never tried it. Instead of refreshing the current UI, when the thread finishes, start a new Activity with the just downloaded content. So first, you start an Activity with a blank page (or just the page's frame), then you rotate the blank page as much as you like, then the downloading Thread spawns a new Activity, replacing the blank page Activity with the loaded content page using the current orientation.

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