Inflater in Android Fragments - android

View rootView = inflater.inflate(R.layout.check_fragment,container,false);
What is the use of a bool as in this case false ?
I am a beginner to Android Programming , can someone explain this to me in detail ?
Thanks in advance.

https://developer.android.com/reference/android/view/LayoutInflater.html
If you set it as true, then the view will be automatically added to its parent (second param). It most of times it should be false, but sometimes it is needed especially when you're using <merge> as root in inflated xml.

true means "please add the inflated View to container as a child for me". false means "please do not add the inflated View to container as a child for me, as other code will handle that later on".
In the case of fragments, you allow the FragmentManager to control adding and removing the fragment's View from its container.
The reason why you need container at all in inflate() is because certain layout manager classes (notably RelativeLayout) need to know their container in order to set up their layout rules properly.

Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML.

From docs:
attachToRoot - Whether the inflated hierarchy should be attached to the
root parameter? If false, root is only used to create the correct
subclass of LayoutParams for the root view in the XML.
In fragments you should pass false as an attach argument, this way the view hierarchy will not be attached to the ViewGroup parent passed in the onCreateView. This attachment will happen later on, Android will take care of it. The container is only passed to onCreateView so you can know about the container where your fragments view hierarchy is going to go.
Actually setting this parameter to true will likely cause exceptions or at least some strange behaviour.

Related

Should I pass the layout's rootview to Snackbar?

As far as I understand we can put any view, such as child view of our root layout when initializing Snackbar.
Quoted from the document:
Snackbar will try and find a parent view to hold Snackbar's view from the value given to view.
However, this statement makes me think of putting the root view might be the best approach. Since traversing the nodes can be taxing especially a layout with a complex hierarchy.
Do I understand this correctly?

What happens to child views when parent is dismissed in Android

I have a custom view in android which is also a container for other views. The child views have certain onClickListeners attached to them. My question is when the parent view is dismissed, does the associated child views and their corresponding listeners also cleaned up or do we need to handle it separately?
Basically any View can be considered as ViewGroup hierarchy with child elements in it. If by "dismissed" your custom View is removed through the call of ViewGroup#removeView (or any similar removal methods) then all its children are removed too.

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

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.

Is it OK to add multiple views to root view of an Activity?

It may sound foolish, but I actually can't find anything on it.
Is it ok to add multiple views to the root view of activity in Android?
So for example I could go like this:
setContentView(R.layout.main);
setContentView(gLView);
setContentView(otherView);
Or simply retrieve it as a view
FrameLayout layout = (FrameLayout)this.getWindow().getDecorView().findViewById(android.R.id.content);
layout.addView(view1);
layout.addView(view2);
layout.addView(view3);
layout.addView(view4);
It all seems to work on devices I test, but is it guaranteed to work on all of them?
Or should I artificially create single FrameLayout to add to root view and add everything to this FrameLayout?
More experiments:
1) if I don't use setContentView and print:
Log.d("Test", this.getWindow().getDecorView().findViewById(android.R.id.content).getClass().getName());
I get: android.widget.FrameLayout
2) If I set content view to for example GLSurfaceView and print the same Log.d
It also prints android.widget.FrameLayout
3) And if I dont' use setContentView at all, and simply do
FrameLayout layout = (FrameLayout)this.getWindow().getDecorView().findViewById(android.R.id.content);
layout.addView(myView);
It attaches the view
So I assume that android.R.id.content returns not what you set by setContentView but the parent of what you set, or the actual root view in activity (which turns out is FrameLayout?)
And I am able to add multiple children to it this way, but question is:
Am I allowed to do that?
Yes, it's perfectly fine to add multiple content Views at the root level. The content Views are simply added to a FrameLayout container, and it is best practice to simply use it for your layout if a FrameLayout is all you require for it, instead of adding an additional container layer.
If you are adding a new content View, then you should use the addContentView() method instead of setContentView(), which would cause the existing content to be replaced instead.
Also, it is possible to add multiple Views to the content container in XML layouts as well by using the <merge> tag, which would just replace the base FrameLayout.
Calling setContentView several times will simply replace whatever view you set before. So what you want to do is create a root view that contains the multiple views you want to add and set the root view to your Activity with setContentView. Your second example with the FrameLayout is a good approach.
Your approach is valid at some extent. but its nice practice to call the setcontentView() once in activity.
this is because it will be very easy to maintain the Activity life cycle and reduce the app crash due to layout leak.
I personally call the setcontentView() once. I define all the layout in single XML file. Afterwords I call setVisibility(View.VISIBLE) and setVisibility(View.INVISIBLE) or setVisibility(View.GONE) to show or hide any particular layout containing my certain views.
Edit
Also its very easy to adjust the layout in XML because you can use simple drag and drop and If you are using relativeLayout then it will be very easy to place any view any where. but in Java code its some how difficult to place the views on your desired position
Hope this helps :)

What happens behind the scenes when an xml is "inflated"?

For example When we write the code
View view = inflater.inflate(R.layout.main_activity, null);
What does the Android system do?
Check out the source for the LayoutInflater. It's an abstract class, a concrete instance of which is obtained through getLayoutInflater().
In essence, the inflater creates a root view object (the root view group of the inflated XML), then does two passes through the XML tree to attach each child view. This is done recursively to handle 'include' and to fix up references between child views, for example in RelativeLayout, and is done top to bottom.
The first pass constructs the tree by instantiating each of the child views, top down recursively, and passes the XML attributes to the view constructor telling the view how big it should be. It then calls measure() for each child passing in restrictions determined by the parent (e.g. RelativeLayout with 2 child views each requesting match_parent) using a measure specifications object and asks the view how big it wants to be. If the view is itself a view group, it will use the same algorithm to measure it's children.
The second pass is the layout pass when layout() is called on each child to position itself within the view. The parent positions the view using the measurements calculated in the measure pass. onDraw() is called and is passed a Canvas created from the DecorView backing bitmap.
The finalised tree is then ready to pass to the window manager which is done by setContentView() or addContentView().
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/view/LayoutInflater.java#LayoutInflater
Inflating an XML layout in simple language means you are converting the XML in View. Then you can fetch each view declared in the XML using the parent/inflated View.
For eg -
View view = inflater.inflate(R.layout.main_activity, null);
Now, here view is the reference of the XML from which you can fetch all the views as,
TextView tv = (TextView)view.findViewById(R.id.tv);

Categories

Resources