I'm reading chapter processing bitmaps off the UI thread in Android training.
In this chapter, the author talks about handling concurrency for GridView when used in conjunction with AsyncTask:
Common view components such as ListView and GridView introduce another
issue when used in conjunction with the AsyncTask as demonstrated in
the previous section. In order to be efficient with memory, these
components recycle child views as the user scrolls. If each child view
triggers an AsyncTask, there is no guarantee that when it completes,
the associated view has not already been recycled for use in another
child view. Furthermore, there is no guarantee that the order in which
asynchronous tasks are started is the order that they complete.
For the above paragraph, I have two questions:
(1) What's the child view of the GridView?
Take the following figure as an example, is every grid a child view?
(2) I'm confused by "If each child view triggers an AsyncTask, there is no guarantee that when it completes, the associated view has not already been recycled for use in another child view."
Can anyone explains more detail? For example, grid[1,1] triggers an AsyncTask, when the AsyncTask finishes, why there may incur a problem?
Yes, Each grid item is a Child View.
The main purpose of an AsyncTask is process long-running jobs off the main thread so the UI doesn't hang. Internally, an AsyncTask uses a ThreadPoolExecutor with a fixed number of threads to manage tasks. So even if you fire off twenty AsyncTasks, only a few of them will be executing at a time. At the same time, since each AsyncTask runs in it's own thread, it might finish at any time depending on how the system decides to schedule your thread. So there really is no guarantee that the tasks will finish in the same order.
When you process images off the main thread, you also need to consider the following scenario.
In AdapterViews, we recycle the child views so that we don't need to initialize new Views every time a View is scrolled on screen. So what will happen in this case is that a Child View will trigger an AsyncTask to fetch the image when it appears on screen.
But before the image is fetched, the user continues scrolling and the view scrolls off the screen and appears again on the other side(because we are recycling the views). Now, it triggers another AsyncTask to fetch the image it is supposed to display. At the same time, the earlier AsyncTask associated with this view completes and sets the Image for this View, even if it isn't the right position for the image.
Related
I have views with hundreds layouts (Linears with TextViews), basically it's like list with data.
My presenter after querying the database (sqlbrite, rxjava, its asynchronous) calling method on view which simply create linear with textviews and adds it to some other Linear (its parent for every added view)
With 100+ rows of data on my older phone there is a freeze. How can I reduce it? I can't add views on other thread than UI of course.
First thing you need to use a recycler view for list of views. and ofcoarse you can use 100 different types of views with ViewTypes of recycler view
Second if you insist not to use recycler view then you may better use AsyncTask for adding views at least. Because in some methods of AsyncTask you can access the UI thread and can add elements.
Third possibility is with event bus. you will add a method to the fragment/activity and register it with event bus. make it run in background from the tag(java tags). and call it from background thread for adding items(views)
Hope some of it solve your problem :) if not get back to me with more explanation of the question.
P.S EventBus is a library work almost the same as BroadcastReceivers but it has more features and its more efficient as well.
I'm building my first app based on material from http://javatechig.com/video/json-feed-reader-in-android.
Everything goes quite ok so far, but there is a bug in thumbnails. When I scroll list, random thumb images quick "refresh" with random different thumb and back to original one. Any suggestion why it behaves like that?
You should take a look at the following page:
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
The part Handle Concurrency explains everything:
Common view components such as ListView and GridView introduce another
issue when used in conjunction with the AsyncTask as demonstrated in
the previous section. In order to be efficient with memory, these
components recycle child views as the user scrolls. If each child view
triggers an AsyncTask, there is no guarantee that when it completes,
the associated view has not already been recycled for use in another
child view. Furthermore, there is no guarantee that the order in which
asynchronous tasks are started is the order that they complete.
So you are right. This is actually a bug of this sample which hasn't got a proper load/display logic.
I want to develop a timeline view for Android, which is like a infinite scrolling Google Calendar day view.
Now I use a fixed length RelativeLayout in a ScrollView, and I think I should use AsyncTask to dynamically load the data.
I do not know if it is necessary to use AsynTask to load the data, because I just want to load some texts now.
My idea is to set two points near the upper and lower borders of the RelativeLayout and load data when scroll across the points. Should I prepare the child views in AsyncTask and attach them to the RelativeLayout in onPostExecute() or create a new RelativeLayout and then replace the old one in onPostExecute()?
What is the common practice? Thanks.
If you're loading the data from a static array or some other data source that is already in memory, you may be able to get away with doing it on the UI thread. If you're going to be loading the data from disk or network, you should (and in the case of network must) load it from a background thread (i.e. not the UI thread), and AsyncTask<> is a great way to do that.
Your approach seems reasonable. You may be able to memoize and reuse layouts as the user scrolls.
My activity is to download and display announcements (from announcements web-service). In order to keep UI responsive I do following actions in background threads:
1) upload XML (data are stored in XML),
2) process XML,
3) upload images.
Besides, I change priorities of UI and background threads to keep UI thread responsive:
in main thread:
Thread.currentThread().setPriority(10);
in background threads:
Thread.currentThread().setPriority(1);
Each announcement is put into a TableRow and each TableRow is put in TableView using handler.
When user scrolls the TableView and is about to reach the end of the table, new rows are added and HTTP-GET for next announcements is sent (+ parcing (using XPath) + image uploading + filling table rows with content).
My problem:
when uploading and parsing is in process user interface is only partially responsive (there are a number of lags 0.1-0.5sec each when user scrolls TableView).
I want to make absolutely smooth scrolling which doesn't depend on data uploading/processing.
What has been done in a wrong way and what else can be done here?
For example, if I diminish number of operations in handler, it should improve responsiveness... maybe like that. However, I see no heavy and resource-consuming instructions there.
UPDATE
I rewrote my code using ListView instead of TableLayout, since the former is considerably faster (as it turned out, I didn't know that). But I still have spikes when XML processing and ListView scrolling were going simultaneously. I made 2 experiments:
1) I removed all background processes - new rows were added to ListView upon scrolling down, but no data were processed for those rows (so they remained empty) - such variant worked great, no any spike, UI absolutely responsive.
2) 2nd experiment was to remove calls to ListView updates (XML file was processed but data found weren't passed to ListView adapter) - that time I had spikes. So I conclude those spikes are due to background threads and are not due to UI update calls.
How can background threads slow my app if I make them have lower priority than priority of main one?
Is
Thread.currentThread().setPriority(some_int);
a correct way to set thread priority?
At some point, the UI thread needs to add these new objects, create new UI objects in memory, and add them to the draw list.
What you could try is to pre-allocate as much memory as you need by making a lot of invisible Table Rows in your UI. This might solve some issues, as potentially the UI thread is trying to reallocate it's memory to make room for your new TableRows.
Also, you could try to use Thread.yield(), in your background threads. This informs the android OS that this thread is ready, and if needed allows the resume of the UI thread (if the UI thread is idle, it resumes instantly).
If you're not doing any I/O on your UI thread, then the lags you describe are probably layout passes. Suggest you focus on optimizing your layout. Is there any reason you're not using a ListView?
I have a problem where calling notifyDataSetChanged() a bunch of times will freeze interaction with a listview for a brief second.
Basically my app loads a bunch of images into a listview. After each is loaded it posts to the ui thread. The ui thread adds the image to a listarray and then calls notifyDataSetChanged().
When you select an image in the list it highlights. When I call notifyDataSetChanged() per image, every one of three taps on the list might actually select. If I throttle down notifyDataSetChanged(), I get a much better rate of tapping and having it select the item.
Anyone have hints on this?
It seems like the 6 thumbs visible (which are unchanged) get thrown out really quick and swapped in again, but the UI shows no indication of them being deleted. During which tapping is an invalid data set.
Don't call notifyDataSetChange() in the UI Thread. it will definitely block the User interaction if it is doing the data call and update the ListView. so do it in the AsyncTask do in background thread which is not doing on the UI thread so it will update the listview when user scroll it