I'm currently using an AsyncTask to make an API call and populate a list with data.
I have a Sub Menu whose items can call the AsyncTask to populate the data, problem is that if i click quickly i end up with merged results obviously cause the AsyncTask is running at the same time as each other.
What is the best way to handle a situation like this? Sorry if this is a amateur question.
I would use a ProgressDialog to show that content is being updated, and when the update is complete, dismiss() the dialog. While this is happening, you should make sure that you are not accepting touch input on your ListView. (this may happen by default when the ProgressDialog is in front, I am not remembering currently...)
Take a look at this link for an example.
You could configure only a single Asynch task to run at a time.
A boolean variable which is set to true as soon as the asynch task starts and set to false as soon as it finishes.
Next call could wait for this to be set to false. You could also rate limit what is the min time after which only making the API call makes sense.
Related
I've got a problem with updating ListView with AsyncTask.
I use ViewHolders to improve performance, but they are causing problems with AsyncTask. As official android website says passing viewholder to asynctask is not a bad idea (http://developer.android.com/training/improving-layouts/smooth-scrolling.html) but in this case, when AsyncTask lasts long enough it updates two items at once with the same value.
I have an impression, that certain viewholder is used again 4-5 items further, and when asynctask does not finish work before passing again the same viewholder bug happens. After a while this viewholder is updating again and have correct value, but it's not satisfying me.
Is my way of thinking right? How to prevent this?
As you know, Views are reused in ListView's.
So you you are starting an AysncTask in every getView(), multiple Tasks might run to load Data in the same View.
Bugs might occur especially while and after scrolling, if the Task take some time to finish.
How to solve this?
Basically you have to make sure, only one(the latest) Task is running for each View.
This can be done, by saving some kind of reference to the last Task in the View.
And if a new Task is started, you have to check for such a reference and cancel the old Task.
A pretty good description can be found here.
The part "Handle Concurrency" should be most interesting for you.
It depends on how your system is set up. If you launch the AsyncTask when the view is requested, yes, your way of thinking is right. Otherwise, I couldn't tell you.
What you could do is add a boolean in your ViewHolder saying "locked". Set that one to true if you launch an AsyncTask, and let the AsyncTask set it to false when it's done. Before launching an AsyncTask, test if the locked boolean is set to false. That way you'll know not to launch another AsyncTask.
I have a activity that show one listview. In the activity I have a one AsyncTask (named here of AsListView) to get values from internet and fill some informations in each item of the listview. Work fine.
Now I created a button in ActionBar to show one image from streetview. To do this I have implemented another AsyncTask (named here of AsImage) to get image from google and show in a DialogFragment, but is necessary wait the execution of all AsListView Threads. It spends long time depending of the number of items in the list.
To execute AsImage rapidily, I cancel all AsListView tasks, but it's not good for me (user loss informations). The ideal soluction is set AsListView tasks to wait while AsImage execute. When AsImage finish I set AsListView tasks to continue execution. But I know that is not possible handle the control of execution of AsynkTasks.....
Some solution?
You can try to synchronize the AsyncTasks using a CountDownLatch.
Otherwise if you want you can use Threads instead of AsyncTasks and set their priorities, but there is a reason android made the AsyncTask class so I recommend you use it.
I have an AsyncTask class that handles all networking calls for my app. I also have a Globals class that holds a progress dialog. Now, what I want is for there to only be one progress dialog at a time; this is fairly simple. The Globals class initializes the dialog, and each time it is used by the AsyncTask, only the message is changed. My issue is determining when to dismiss it. If I use p.dismiss() at the end of onPostExecute(), then the progress bar will go away until the next AsyncTask runs, which is not what I want. However, if I don't include the line there, then the progress dialog will stay up indefinitely. I guess what I'm trying to find is a way to see if all AsyncTasks have finished running. By doing this, then that one global progressdialog will be able to close without looking wonky.
Chaining together all the AsyncTasks is not an option (e.g. having the first one execute the second in its onPostExecute()).
Also note that there could be anywhere between one and five AsyncTasks running at the same time.
How can I determine if every AsyncTask is complete?
you could keep track of how many you are starting and create a callback to the class every time a task finishes, then when the returned count matches the start count you know all the tasks are done.
there really is no way to know when see what tasks are running without doing some thing like that.
there is a getStatus but you would have to keep polling for the status to see if the individual task is done or not
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.
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().