Android How to synchronize a Layout view? - android

I have a TableLayout, within a ScrollView, which is updated constantly by an AsyncTask.
I don't know if it is "legal" to add/remove rows by the AsyncTask when at the same time the user may be scrolling the TableLayout.
How can I make sure the update does not interfere with the Scrolling in the GUI?
Or does the OS take care of this for me?

On Android, the main thread that your Application runs on is the only thread that can update the UI. If you try to modify the contents of your layout from within an AsyncTask, you'll get an error. AsyncTask's onPreExecute and onPostExecute methods, however, ARE run on the main thread, so you can update the UI there.
So, to answer your question, yes the OS takes care of this for you by not allowing asynchronous UI updates.

Related

Handle Concurrency for GridView when used in conjunction with AsyncTask

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.

Advice on developing a timeline view for Android?

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.

Android: using multithreading to make UI responsive (archieve smooth scrolling)

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?

Android smoothScrollBy behaving badly

I have a ListView that I am calling smoothScrollBy() on. 95% of the time, the smoothScrollTo() behaves as intended. However there are times that it does not end up in the intended spot! I have verified that I am giving it the same value. I notice that the smooth scrolling is not so smooth when the errors are made, however there are no other tasks that my application is performing that I would have control over.
I am not quite sure what is going on in the background but a likely culprit is garbage collection.
95% accuracy is not good enough in this situation. I am going to have to implement some sort of a correction mechanism to make sure the ListView lands on the correct spot in these instances.
Is there a better way to use smoothScrollBy() other than simply calling view.smoothScrollBy(distance, time);?
sometimes it will be because of the timing issue. When the views are added to your listview and the time you do
view.smoothScrollBy(distance, time);
the listview or the ui still need not get refreshed. So do this in the views post thread with a specific delay. Eg.
view.postDelayed(new Runnable{
view.smoothScrollBy(distance, time);
},1000);
Try some of these:
Listview has its own scrolling mechanism. It scrolls when the content is added.
Assign listview height (android:layout_height) to match_parent or fill_parent.
If your assigning a adapter in a working thread. Do not perform any UI actions in the thread.
If these do not solve the issue. Please post the code where you assign the adapter to the list view if any. Or the relevant code.
Also the xml layout code.
Hope this helps.

Refresh layout while filling it

I have an activity with a HorizontalScrollView. When it opens, I start filling this view (or rather, a container layout inside it) with another views. This is done from another thread by using handler.post.
The views are added in bunches of 15, and when there are no more views to add, I start updating them with new data (this is a kind of streaming data from a server).
The problem is that the scrollview is empty until all of the views are added. As soon as they are all added and start updating, the scrollview gets drawn.
How do I refresh it in the process of adding views? I don't want the screen to be empty for 3 seconds while all of the views are added.
Thanks a lot.
UPDATE: turned out this problem is not specific for HorizontalScrollView, this is the case for any generic layout.
Im not sure I understand exactly how your program is constructed, so that the views are not shown until you start updating... but perhaps myLayout.forceLayout() helps?
The thing is ofcourse that layout only gets shown after onCreate().
I could imagine you use a AsyncTask to perform data lookup and use the callbacks provided in that class to update the UI, since they run on the main thread. This way you can just finish the onCreate(), and then start updating your view.

Categories

Resources