My app contains a viewpager and each page fragment is laid out as so:
<ScrollView>
<LinearLayout>
...
other views
One of these 'other views' is a LinearLayout populated at runtime in a loop. Each item is inflated from xml. I've determined each call to LayoutInflater.inflate() is taking avg 4-6 ms. Between all my fragments and some containing more than one of these 'dynamically populated lists' i'm inflating 40-50 of these child layouts during startup and it's adding up to a lot of skipped frames.
I'm looking for a less expensive way to create all these views.
All the child views within one list are the same, is it possible to inflate one and copy it to another instance in a way that is faster than calling inflate()?
Is it possible to reuse these views similarly to the way a listview does?
One last potential solution, would it be faster to create these child views manually rather than inflate them from xml?
So to summarize the question, looking for the least expensive ways to create views in code. thanks for reading.
Related
I have a ListView where each row of the listview contains about 10 ImageButtons. Most of these buttons have visibility = Gone and only show up in very rare scenarios. I am wondering if it's worth it to replace these ImageButtons with ViewStubs to avoid loading them (and the images they contain) all the time for all the rows of the listview. Then again their visibility is set to "Gone", so I am not sure what impact loading them has. Do their images actually get loaded or not?
Note that I am talking about replacing e.g. the 8 ImageButtons with 8 ViewStubs, not with 1
Cheers
A ViewStub is a dumb and lightweight view. It has no dimension, it does not draw anything and does not participate in the layout in any way. This means a ViewStub is very cheap to inflate and very cheap to keep in a view hierarchy. A ViewStub can be best described as a lazy include. The layout referenced by a ViewStub is inflated and added to the user interface only when you decide so.
Sometimes your layout might require complex views that are rarely used. Whether they are item details, progress indicators, or undo messages, you can reduce memory usage and speed up rendering by loading the views only when they are needed.
Simply a ViewStub is used to increase efficiency of rendering layout. By using ViewStub, manually views can be created but not added to view hierarchy. At the runtime, can be easily inflated, while ViewStub is inflated, the content of the viewstub will be replaced the defined layout in the viewstub.
The ViewStub will be loaded only when you actually use it/need it, i.e., when you set its visibility to VISIBLE (actually visible) or INVISIBLE (still not visible, but its size isn't 0 any more). ViewStub a nice optimization because you could have a complex layout with tons of small views or headers anywhere, and still have your Activity load up really fast. Once you use one of those views, it'll be loaded.
You must add ViewStub in Layout at first, after you can inflate it to another View.
Note: One drawback of ViewStub is that it doesn’t currently support the <merge/> tag in the layouts to be inflated. Alos ViewStub can’t be used more than once. Also keeping long-lived reference to a ViewStub is unnecessary, if it is required, it's good practice to null it after inflating, so GC can eat it.
Let's suppose your ViewStub ID is view_stub. You need to do the following in the activity:
ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
View inflatedView = viewStub.inflate();
ImageButton button = (ImageButton) inflatedView.findViewById(R.id.button);
Now you can do whatever you want with the button :) That is, the inflate method returns the stub layout which contains the actual elements from the XML file.
Of course, you can always have the onClick XML attribute or can be dynamically called.
Is a ViewStub worth it?
->For the scenarios that you are specifying, I think `ViewStub` will be worth-shot.
See below urls about ViewStub
http://android-developers.blogspot.in/2009/03/android-layout-tricks-3-optimize-with.html
http://developer.android.com/reference/android/view/ViewStub.html
http://developer.android.com/training/improving-layouts/loading-ondemand.html
Instead of ViewStub you can try <\include> tag. The <include/> will just include the xml contents in your base xml file as if the whole thing was just a single big file. It's a nice way to share layout parts between different layouts.
Difference between <include> and <ViewStub> in android
Edit: just noticed that Endzeit commented regarding a similar direction before me.
I would start by doing some benchmarking around the inflating code with and without the views - just comment out the adapter code so it doesn't try to access the non existing views.
If the removal of the Views from the layout does gives you an improvement that you think is necessary and since you say the views are present only in rare scenarios which you are anyway checking for in your adapter,
then instead of inflating those views or even using view stubs, create them in code and add/remove them as needed (using the viewholder to reference them).
You could even go further and do a lazy creation of these views, similar to lazy loading of images, but I would only do that after running some benchmarking again.
I would use ViewStubs for loading complex layouts not simple ImageButtons.
Edit 2:
Looking into ViewStub inflate command, which is what it does when it needs to be visible you can see it infaltes the layout given and then adds it to the parent layout - since you are adding a simple ImageButton you can gain performance by not having a ViewStub and just adding the ImageButton in your code.
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/view/ViewStub.java#ViewStub.inflate%28%29
According to Google's official documentation here.
ViewStub is a lightweight view with no dimension that doesn’t draw anything or participate in the layout. As such, it's cheap to inflate and cheap to leave in a view hierarchy. Each ViewStub simply needs to include the android:layout attribute to specify the layout to inflate.
To experiment this, I created a sample project and added a ViewStub to the layout hierarchy. On running layout inspector I can see that all the layout attributes for ViewStub are zero.
Let's compare it to having a layout which has 10 buttons hidden. What this actually means is, the layout hierarchy has 10 buttons hidden, which is sitting in the layout hierarchy and taking up some amount of memory. It's cheap to leave a ViewStub in hierarchy since it doesn't take up much memory, at the same time it's cheap to inflate.
My final verdict would be, use ViewStub extensively when you've complicated views which are inflated rarely as it definitely helps in saving memory and improving View inflating time.
Using the Android monitor's Memory tab in Android Studio (button for the Android monitor should be at the bottom bar), you could check it yourself:
Take a look at the memory usage when running the app with invisible buttons
Take a look at the memory usage when running the app with visible buttons
If there is any difference, then you can conclude not everything is preloaded when the views are Gone. Of course, you could also compare this to a ViewStub implementation to check whether that will help to decrease memory usage.
In short, using custom view instead of viewstub.
We are having a similar situation now, and we have also tried viewstub before, listview works a little faster. But when it comes to 8 viewstubs, i don't think its a good idea to use viewstub to avoid inflate too many widgets.
Since u (and also us) have a logic to control whether 10 buttons to show or not , why not just define a custom view, and draw different buttons according to different state machine? It's much fast, and need no inflation at all, and it's logic is much better controlled. We are using this method to accelerate listview now and it works good.
when you set a view visibility to gone this means that This view is invisible, and it doesn't take any space for layout but its data are loaded into it.
Now the ListViews they remove the unseen or lets say the views that are out of the screen bounds for performance reasons .
A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime.
So i think if you want from my opinion I prefer the Views with GONE Visibility rather than using much logic with ViewStub and Creating and inflating ... etc .
But on the other hand
The rendering performance comes into picture when you are inflating
the views.
My guess is that its much cheaper to inflate a ViewStub than to
inflate a View, either from XML or by changing visibility. ViewStub is
especially used when you need to add/remove (indefinite) views (eg.
add phone numbers to a given contact). Hope this is what you were
looking for.
reference : ViewStub vs. View.GONE
some good Brief presentation of DDMS here :
http://magicmicky.github.io/android_development/benchmark-using-traceview/
Use ViewStub instead ImageButton.
This is because
. ViewStub is zero sized view by default while image button not
. View Stub is naturally an invisible view . its performance is better than image button because it load runtime only when its state become visible.
I am going to start one app where my activity page will contain "n" grouped views. Grouped view means "collections of views (i.e. One group can have TextView+Button+ImageView)". So the page will have "n" number of such grouped views.
I need suggestions like what would be the best practice to implement this. I could think of below ones:
1) Should a ScrollView be used (Then I will have to create groups in runtime and place one under another)?
2) Or a ListView be used (Then how can I accommodate the height of each row as grouped views height may differ from each other?)
Or is there any other way I can go along with?
Appreciate the suggestions and any sample examples if have. Advance Thanks.
Both options would work, it really depends on your use case.
Place a vertical LinearLayout inside of a ScrollView and add your grouped-views to the LinearLayout. I would recommend this if you have a relatively small number of such views (not necessarily a fixed number, but small enough that you wouldn't have to scroll many "pages" to see them all). Make sure the ScrollView has android:layout_height="match_parent" and the LinearLayout has android:layout_height="wrap_content".
If the number of grouped-views is not small, you could use a ListView and make an Adapter for it. This lets you take advantage of ListView's automatic view recycling when items get scrolled off screen.
For either case, make an XML file for just the grouped-views. In code, you would get a LayoutInflater object (usually by calling Activity.getLayoutInflater()) and call inflate(R.layout.your_grouped_views, null). If using the LinearLayout, you would add it in code with one of the LinearLayout.addView(..) methods; if using the ListView, your adapter would return the whole thing from getView(...).
create one xml layout containing the constant elements of your group view.
in you main xml layout which will be the contentView of your application, put a ScrollView and a single LinearLayout.
then in the program inflate as many views of your group view as you want.
For your answer i want to give you referance of this website, on this website you can learn create dynamic view in android...
Say I have an activity showing informations on an object: the name, a little description, a photo. Below this informations I have a list of comments. Obviously the number of comments displayed is not fixed and the list have to be created dynamically. Now I want ALL the activity layout to be scrollable, so I added a ScrollView as parent of all other Views. But in this way, I can't use a ListView to show the comments, because it's not possible (or it's very discouraged) to wrap a ListView inside a ScrollView. I'm compelled to use a LinearLayout, cycling on the comments list and inflating (I want to keep layouts in xml) multiple times the same layout, which brings to other drawbacks like the confusion on items ids.
Note well that even trying to reduce the complexity showing a prefixed number of items in the list (say showing N most recent), it would be very annoying to embed in the xml definition of the LinearLayout a fixed number of list items, because changes in N would affect both code and xml.
Which could be a optimum design to face all this problems:
Keep all the activity layout scrollable.
List a variable non pre-fixed number of items in a portion of the UI.
Keep the definition of the list item layout in the xml.
Prevent inflating multiple times the same layout.
I can't figure out that in android it is not possible or it's necessary to use some kind of workaround to achieve this common behavior.
I typically organize my code/logic by a fragment represent one layout. Now I am in need of few relatively simple forms to get input data from user, which are somewhat related in purpose.
Say I hav 3 screens, and I could create 3 fragments to handle them (display view, read input, submit, ..). Or should I use one fragment, and use FrameLayout create a stack of layouts. I was thinking like, stacking all 3 views and hide/display the view I like. But the documentation say
Generally, FrameLayout should be used to hold a single child view,
because it can be difficult to organize child views in a way that's
scalable to different screen sizes without the children overlapping
each other
Any good way to do this or should I create multiple fragments for this (the down side of this is lot of small classes and repeated code. I may use a base class, still like to explore other options)
Thanks.
It sounds like you don't really care that much if the views overlap each other in the FrameLayout, or in fact they are supposed to overlap because you expect to be showing only one at a time. FrameLayout can certainly display stacked child views that each take up its full width and height just fine, and if you set the visibility of the unused views to INVISIBLE or GONE, they will not intercept screen presses or take focus if they happen to be located above the visible view the user is interacting with.
On the point of readability and code maintenance, I think swapping fragments makes more sense though, even if there is more memory overhead. The layout management can be encapsulated within the individual fragments, and you do not need to worry about showing/hiding views, as fragment transactions will take care of that aspect.
I have a ListView with layouts in them. Sometimes the layouts need to look one way, sometimes the other. They are mainly text laid out in different areas with different weights sizes etc. The ratio of main views compared to other views is about 5:1. When it needs to be changed only 2/3 of the whole view changes.
I think I have two options :
(the way it is now) One layout(so it never has to be re-inflated, as the recycled views are all the same) and the 2nd 2/3 of the view is hidden until it is needed to be changed, then code will reveal it and hide the original 2/3 of the view.
(other way) Two layouts, with the 1/3 layout duplicated, and each having its on other 2/3. Then when one of the different layouts needs to be used, the old view from the ListView recycler gets thrown away and a new correct view is inflated, and back again when the list is moved.
So what I am asking here is that is it better to hide/show parts of the same layout to prevent the recycler in a ListView from inflating more layouts, or have two cut-down layouts with no extra hidden views, and have them inflated when they are needed?
If the TextViews are the main part of those layouts, I don't think there is going to be a big difference in performance so you could go either way. I would go with option two because:
The ratio between the number of normal rows layout vs special rows is big. If you keep the single layout approach then you'll have to modify the layouts in code for each of the rows, normal or special, because you could be dealing with a recycled View that has 2/3 part hidden when it's time to show a normal one(so you end up modifying the layout each time). If you were to use the second option then you could eliminate this part from the getView method and simply use a switch to see with what row type you're dealing with(no more modification of the row layout each time in the getView method, you let the ListView handle that by providing you with the correct type of row layout). Don't worry about inflating another layout file(once), this isn't the performance hit to be afraid of.
Using one type of layout it means you're having Views remaining in memory even if the user doesn't see them(so you may be preventing the ListView from inflating more Views(only one time, in fact) but at the same time you're occupying more memory with the ones you even don't show to the user). The first option has the advantage that the binding of data to the row is more simple as you have all the views at your disposal(even if the user doesn't see a part of them) instead of the second option, where you would have to see which data need to be shown based on row type.
Code readability. Having two row types and testing to see which one you get in the getView method it's more meaningful as you see what logic you have for each type of row. Also, it will be better if you plan to change those row layouts in the future or add more row types.
The ListView does a great job on recycling views as long as you help it with providing the row types.
Edit: The ListView will keep a recycled view for each type you declare in the adapter. So the ListView will inflate the second layout only the first time it finds it in the ListView, next time when it will need a row with with type it will use the recycled one(and it will maintain 2 types of recycled views, the first and second row type).
Actually this little bit of extra GC IMHO should not be the driver for your decision.
I would go the route that is easier to maintain and understand.
Also there is an nice useful include tag in xml like this:
<include
android:id="#+id/abc"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
layout="#layout/abc" , where abc = the xml file you want to include
/>