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.
Related
I am having nested scrollview with 100 layouts. All layouts are initially will be empty. When user scrolls and stops the scroll I will send request to the server and update the layout. I am facing issue doing both parallel. When request sent to server and receive response I am updating the layout using following code:
((Activity) ctContext)
.runOnUiThread(new Runnable() {
public void run() {
reDesignLayout(layoutID);
}
});
But the problem is I am not able to scroll the scrollview while updating. I tried with Handler and runOnUiThread. But both not able to scroll. Please help me on this.
I think the using of the Scrollview isn't suitable for your case.
Try to switch to RecyclerView with an adapter.
Benefits:
low memory usage
handling appear/disappear states of each item (the layout in your terms), you can start/stop/resume network call to reduce a workload on your server and etc..
flex the layout setup of each item.
If you want to update data in that process, you would need to create an id, find the view, and assign them each and every time. That would mean you would need to write code to assign 100 different ids to 100 different containers containing your views.
And assigning values to all of them would be a real pain, if not unreal. And it's not at all advised for this case.
Instead, I would recommend using a recycler view. Which is the best that is available. It decreases the amount of code you write and the memory space needed as it is based on the concept of reuse and helps populate data efficiently.
You could visit the link below, to learn more about recycler views. Hope it helps.Happy coding!
https://guides.codepath.com/android/using-the-recyclerview
I am actually developing an Android application on which I should display dynamic forms based on metadata contained inside JSON documents. Basically the way it works (without the details) is that a JSON document represent the structure of a form:
{
"fields": [
{
"name": "fieldA",
"type": "STRING",
"minCharacters": 10,
"maxCharacters": 100
},
{
"name": "fieldB",
"type": "INTEGER",
"min": 10,
"max": 100
},
{
"name": "fieldC",
"type": "BOOLEAN_CHECKBOX",
"defaultValue": true
}
...
],
"name": "Form A"
}
What I'm doing actually when the application receive one of those JSON documents is that it loop through each fields and parse it to the appropriate view (EditText, Checkbox, custom view, etc.), adding a tag to the view (to be able to retrieve it easily) and add the view to a LinearLayout. Here is a pseudo-code of how it is working actually:
//Add form title
linearLayout.addView(new TextView(form.name));
//Add form fields
for(Field field: form.fields) {
View view;
switch(field.type){
case STRING: view = new EditText();
...
}
view.setTag(field.id);
linearLayout.addView(view);
}
The issue with this is that with large forms (like >20 fields), it need to inflate lot of views and the UI thread suffer a lot. Another point to take into account is that a single screen may have multiple forms (one after another vertically sorted).
To avoid overloading the UI thread I thought of 2 possible solutions:
Using a RecyclerView.
Using Litho by Facebook.
But multiple questions comes to me when considering these 2 solutions:
Is it a good use case to use Litho? Or using a RecyclerView is enough?
What about the state of my views? If I use a Recycling pattern, would I be able to keep the state of each of my fields (even those off-screen) and so being able to save the form without losing data?
If I use a Recycling pattern to display one form, how would I handle multiple forms? Can we have nested RecyclerView? Forms need to be displayed one after another like inside a vertical RV but if forms themselves are RV, how should I handle this?
This is more a "good practice" question and giving the right way or one of the right way of achieving my goal than a need of a specific answer with code example, etc.
Thank's in advance for your time.
When architecting for the mobile application I would like to address the following questions:
Is it a good use case to use Litho? Or using a RecyclerView is enough?
Are the views are being recycled properly:
What does it mean to us is consider, creating 40-50 view per screen and as user moves out of the view, system should not mark all views for GC rather it should be inside some kind archived list and as we require it again we should be able to fetch from it.
Why do we need to that: GC is the costliest operation which would cause app rendering to be jitter, we try to minimize the GC to called at this point by not clearing the views
For this I would like to go with litho, justification is here as your requirement seems to have more of variable count of viewtypesreference
Conclusion: Litho +1, RecyclerView +0
What about the state of my views? If I use a Recycling pattern, would I be able to keep the state of each of my fields (even those off-screen) and so being able to save the form without losing data?
Saving EditText content in RecyclerView This is one the component but same logic should be appliced to checkbox or radiobutton as well. or as in state-maintenance for litho is here
Conclusion: Litho +1, RecyclerView +1 both has specific API's to achieve state maintenance
If I use a Recycling pattern to display one form, how would I handle multiple forms? Can we have nested RecyclerView? Forms need to be displayed one after another like inside a vertical RV but if forms themselves are RV, how should I handle this?
This has to be addressed with user experience plus technical capability: As per user behaviour IMHO,I discourage the nested vertical scroll however others were able to achieve it you can easily find on how to in SO. Optimal solution would be to have horizontal scroll within either Andriod's or litho's recycler view as here
NOTE: If you need to know implementation details, please raise it as separate question, I would be happy to help there
UPDATE #1:
The issue with this is that with large forms (like >20 fields), it need to inflate lot of views and the UI thread suffer a lot.
UI creation/layout has to be performed at the backend only adding to the view has to be done on UI thread. And litho does it in-built. However same can be achieved native recycler view as well but you have to move off the UI thread and post periodically to UI.
Ok, you have two separate problems here. One is overwork the UI thread, and the other is to keep the state of your anonymous views. About the first part:
1.-Litho could help you with this. But you have to move all your logic towards litho components instead of android widgets. Since I don't know your codebase, I don't know how hard this can be. A recyclerview would help with view recycling, but that only matters if you are well, using a list.
2.-It could, as long as you have a way to keep a representation of the widget's state that you can pass to the adapter and then back to the view (I'm assuming you generate all the windows by code and then have zero reference to them) and so. It sounds messy, and it is messy, so I won't try it.
3.-You can, but is messy. Best approach in this case would be having horizontal recyclerviews inside a vertical recyclerview. Nesting recyclerviews inside another recyclerview with the same direction creates funny problems, like "Why this cell is not scrolling". I would avoid using the recyclerview as a parent if the view does not need it.
Now, to the solutions:
A) UI Overloading: According to your pseudocode, you aren't inflating stuff. You are creating java objects which happens to be subclasses of View. That's good, because creating objects in a background thread is far easier than inflating (Parsing XML and use it as arguments to generate identical copies of a given resource by invoking constructors) stuff in a background thread. While a LinearLayout context constructor requires an UI thread to be executed, other things, like textviews, don't. So you can create the latter ones inside an asynctask and after you are done generating your whole hierarchy, execute the methods that need the UI thread and add the generated layout to the window. For the view classes that don't support being created as java objects asynchronously, you can have an XML file with just that component, like the linearLayout, and create then asynchronously with the support package asyncLayoutInflater. this solution can be implemented in any codebase and would allow you to make your UI generation completely asynchronous.
B)Keeping track of the view state: Again, I'm assuming your view hierarchy is anonymous. If so, what you need is to generate an interface you can use as a contract to invoke both state saving and state loading from a lifecycle aware component, like the activity. After creating such interface, subclass the widgets and create a subscription/event bus system in each widget that saves/loads the state from the widget every time is triggered. That way, each of of the components on the screen would be able to remember their state while remaining anonymous.
Just use the RecyclerView and create views on runtime (you are not inflating, you are instantiating)
Dynamically creating and adding views should not slow the UI thread considerably on mid-range devices. If it does, do investigate for bottlenecks elsewhere
You can perform a simple benchmark by adding/removing/setting text with lots of views dynamically inside a RecyclerView or even a LinearLayout hosted by a ScrollView, and you'll see it goes smooth
Use jetpack composer provided by android
https://developer.android.com/jetpack/compose
I have an android app that I'm developing using Xamarin. The app contacts the server and, via web service (SOAP), receives a list of objects. Currently, in my axml file I have just linear layout (ll) within scrollview tags and nothing else. In the code, I loop through the collection and new up the elements that I want and attach it to a layout. Once I'm done with each record, I attach (i.e.AddView) to the master layout (ll). Everything works.
I have a couple of concerns and I appreciate some feedback on it.
1) Each object in the list contains an URL to an image online. Currently, for each object, my process downloads the picture individually. Would ListView give me any advantage of reusing (caching , etc.) an already downloaded picture even though other attributes of the objects are different? Will there be any gain in terms of network utilization if I switch to ListView?
2) Is drawing elements by hand (like I'm doing) an acceptable best-practice?
Thanks all.
Definitely use a ListView. There is a great article here by Lucas Rocha that outlines exactly why ListViews are beneficial and how to make them perform even better. To give you a few examples, ListViews minimize the number of view inflations you do, and they only create the list items currently visible on the screen or about to become visible on the screen.
This is a huge improvement from your approach, since your current method would load every element in the list before presenting the activity to the user. Therefore, drawing elements by hand like you're currently doing is definitely not best-practice.
Also, for displaying images from URLs in your Xamarin app, I highly recommend that you use the Xamarin component UrlImageViewHelper. Despite being incredibly easy to implement in your app, it will improve performance drastically since it takes care of image caching and async image loading.
I have an adapter that displays a grid of thumbnails with a text. These thumbnails are heavy to load, heavy to draw, etc.
The thumbnail gridview is constantly filled with new content, let's say, 1 new item every 2 seconds.
My adapter has a function that I call from outside to inject new items:
public void postNew(Item i) {
arrayStuff.put(i);
notifyDataSetChanged();
}
What happens is, with my current approach, when I insert a new element in the gridview, it refreshes everything, even if the added item is not going to be visible. The refresh process kind of breaks the experience, specially if the user is browsing the gridview and new content arrives.
How would you recommend improving this? is there a lighter 'notifyDataSetChanged()' or something like that?
I do not know of any lighter version of notify data set, but you can always use ListView.getFirstVisiblePosition and ListView.getLastVisiblePosition to determine whether your latest added position is visible, and only call notifyDataSetChanged if it is.
As for "heavy" bitmaps, as heavy as it is I think you should resample or scale it to the minimum size you need, using LruCache you can reduce the need of re-drawing on notify data set changed.
It sounds like you probably need to implement some form of caching, it's not very good memory management to have images which are not visible loaded into memory, ideally you would retrieve them from cache when they become (or are about to become) visible.
An alternative approach could be to add some form of visual indicator when new content arrives and then implement "pull down to refresh" or similar, then make a call to notifyDataSetChanged() on your adapter to refresh the content. I can imagine that refreshing every couple of seconds would not give a great UX because it would be hard to follow if the screen content is constantly changing.
You need create custom view(dynamic at runtime) that adds multiple imageview and appropriate textview, the container view should be LinearLayout, after that you can able to update a particular view or element.
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?