Android Performance : Adding view programmatically vs setting view to GONE/VISIBLE - android

I'm working in a project that requires to inflate a simple tutorial View when the user opens the app for the first time. I'm trying to do it "the right way", and I'm wondering about performance issue.
Currently, I have in my layout a view sets to android:visibility="GONE", which I change to VISIBLE depending on a SharedPreference. This allows me to let the user learn how the app works on first launches.
What I'm wondering is what it implies when the view is rendered in my Fragment. My guess is that the view will be uselessly inflated, even if its visibility is set to GONE.
Now, I'm thinking about an alternative: what if I would only add my View on first launches, but programmatically, in my Fragment's onCreateView. That should allow the view not to be inflated on later launches, but wouldn't inflating the view programmatically implies bad performance on first launches?

So, to answer my own question I used the DDMS tool TraceView to monitor the calls from my fragment onAttach until its onResume. It let me see which implementation are the less efficient.
To do the test, I had a simple RelativeLayout with a FrameLayout inside it (shown all the time). I used a custom layout to add each time, either programmatically or with a visibility of GONE on my layout file. The custom layout was composed of a RelativeLayout with 4 childs (an ImageView, a TextView, a View, and a Button).
My onCreateView was the following, allowing the app to inflate the right layout based on two static final boolean constants to change the layouts.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
LinearLayout root;
if(INFLATE_PROGRAMMATICALY) {
root = (LinearLayout) inflater.inflate(R.layout.fragment_test_prgmcly, container, false);
if(SHOULD_FYI_VIEW_BE_SHOWN) {
View tutoView = inflater.inflate(R.layout.inner_view, root, false);
root.addView(tutoView);
}
} else {
root = (LinearLayout) inflater.inflate(R.layout.fragment_test_gone,container,false);
if(SHOULD_FYI_VIEW_BE_SHOWN) {
View tutoView = root.findViewById(R.id.RL_inner_view);
tutoView.setVisibility(View.VISIBLE);
}
}
return root;
}
This lead to the following results:
When the optional layout in inflated
SHOULD_FYI_VIEW_BE_SHOWN=true
The maximum "real time estimate" given by the TraceView are of 75ms when there is just a view to change from GONE to VISIBLE, but of 110ms when we need to instantiate the inner_view.
When the optional layout isn't inflated
SHOULD_FYI_VIEW_BE_SHOWN=false
In this case, the maximum real time estimate given by TraceView are of 102ms for the inflation of the GONE view, versus 39ms when the view inflated doesn't have the GONE view.
So, for the performance gain when the views doesn't need to be inflated, I'd say that the best solution is to inflate your view programmatically if you only need to show it a few time.
You can find the test project on a Gist

I think you are reinventing a wheel. For this scenario is already existing tool in Android xml layouts. It is called ViewStub. You can read more here: Loading ondemand

I think I just randomly stumbled over the answer of your performance question.
From the Animation Docs:
For the view that is being faded in, set its visibility to GONE. This
prevents the view from taking up layout space and omits it from layout
calculations, speeding up processing.
This would mean performance is not compromised as long as you don't set android:visibility to anything else than GONE.

Related

Is it possible to enable touch events for a View inside a ViewGroup but outside its bounds?

I'm currently trying to design a ViewGroup (specifically a subclass of FrameLayout) that can layout any number of subviews and enable them for drag/drop outside the layout group. It's almost identical to a LinearLayout:
Curently I am able to drag the views outside the ViewGroup and draw them, however after letting go of the view it can't be re-selected and further dragged around.
I'm wondering if there is a way to do this in a way that isolates the logic to the Layout subclass and doesn't involve needing to do much/any extra stuff in consuming fragments/view groups.
I've tried overriding getHitRect(Rect) in my FrameLayout subclass but it never seems to be called. dispatchTouchEvent(MotionEvent) is of course not called either, presumably because the parent ViewGroup has decided not to deliver the touch to it because it was outside the bounds. I've tried implementing a TouchDelegate as well, but I think that needs to be set on the parent view, which means needing to know about this and doing this additional step when using this Layout.
Any ideas on if/how this is possible? On iOS it can be implemented fairly easily by overriding hitTest: to take into account the frames of the child views. Is there a similar method like this on Android?
Your help is greatly appreciated!
Without any code it is very hard to see what you are doing, but best guess would be that each view should a child view of the relative layout.

What are the benefits of extending LinearLayout over View?

I am trying to build a soundboard app that plays a sound whenever you tap on a custom view. In order to organize my UI, I used a layout file.
When I extended View, I found that when I tried to inflate my layout, it wouldn't work.
//Didn't work
View v = View.inflate(context, R.layout.sound_view_layout, null);
When I extended LinearLayout, however, it did work.
//Worked
View v = View.inflate(context, R.layout.sound_view_layout, this);
My question is,
how come I needed to extend a Layout class in order for the program to work, and what are the benefits of doing so?
Well you can only inflate a layout. If you want to just create a View, use new CustomView(context).
Ignoring that- the main reason to extend a layout is if you want to add children to it programmatically, or if its a collection of views already (for example you may want to create a view CaptionedPhoto that has an image on top of text. One way to do this would be to make CaptionedPhoto extend LinearLayout and hold an image view and a text view).

Android - Is a ViewStub worth it?

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.

Converting RemoteView into a View

I am trying to render a RemoteViews instance onto a Canvas, like I do with a regular View. I use
RemoteViews.apply(context, null)
and it returns a FrameLayout with all the views nested and properly measured (location and size is correct,) but after using .draw on the returned view, it renders all elements with no values -- TextViews are empty, AnalogClock is reset at 00:00 and so on.
Any ideas? I'm lost :(
Not sure if the question is still actual. Nevertheless here is my experience with RemoveViews. It appears you cannot just call draw() on the returned view. You have to add this view to a parent container to make it a part of global view hierarchy. For instance, you have an Activity with a single FrameLayout in it. Your code will look like this.
FrameLayout parent = findViewById(R.id.container);
View view = RemoteViews.apply(getActivity(), parent);
parent.addView(view);
Now you should be able to see tests. If you set listeners, they will work properly too.

Android GLSurfaceView as subview

I'm very new to an Android platform and currently trying figure out why things work this way:
If I create GLSurfaceView and add it using the setContentView or addContentView to an activity everything works fine (Renderer.onDrawFrame is called as expected). However if I add my GLSurfaceView to another ViewGroup (which is then added using setContentView) nothing is rendered.
So what is the difference between addView and addContentView ?
In the end I need to create a custom view with OpenGL rendering in background and some controls on top.
Also what is the point of separating View and ViewGroup? Why not to join them (like it is done in CocoaTouch) ?
setContentView(View) sets the parent View for an Activity (or dialog etc...).
addView(View) adds a View to a ViewGroup.
View and ViewGroup are mostly different. View is a more specific single entity. It should be used more on one facet of what you are trying to do. ViewGroup, however, focuses more on the whole and acts (is) a container and layout organizer for a collection of Views.
Can you post all the code related to the GLSurfaceView and how you are setting it as contentView?

Categories

Resources