I get an Error
07-04 01:49:56.325: E/AndroidRuntime(9693): java.lang.NullPointerException
while try to inflate ViewStub in Fragment after transaction done
sendMessageView = ((ViewStub) rootView
.findViewById(R.id.send_message_viewstub)).inflate();
Here are XML
<ViewStub
android:id="#+id/send_message_viewstub"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:inflatedId="#+id/panel_import"
android:layout="#layout/fragment_send_message" />
Agree with Shawnic, that error line you are showing us doesn't tell much. I can tell you that using fragments is a little trickier than activities.
But with that said, I don't think you can use a fragment as the included layout?
What or where exactly is the Fragment within the context of your question?
Fragments have their own class files that take care of inflating a layout to be used as the Fragment.
Also I am concerned about this part you posted:
sendMessageView = ((ViewStub) rootView
.findViewById(R.id.send_message_viewstub)).inflate();
Now I have experience with this but it's been a while and I am not sure if this part of your code is correct?
This is how Android recommends you write it:
ViewStub stub = (ViewStub) findViewById(R.id.stub);
View inflated = stub.inflate();
In Your Code, what kind of object is
sendMessageView
You may want to change your code to this first just to make sure, we don't know exactly why Android suggests we do it this way but we probably should.
If you're always going to be inflating the same layout in this ViewStub, you would be better served using an include tag.
<include layout="#layout/fragment_send_message />
include replaces itself with the specified layout at runtime and allows your layouts to be both modular and readable.
Related
I'm new to Android and have recently started adopting the pattern to create an auto-layout-loading custom view based on a layout file. In the layout you use the 'merge' tag as the root, then in the constructor of your view, you inflate that layout into yourself so you are essentially the root of the merged-in controls. Right after you inflate, still in the constructor, you can find the child controls from the layout and assign them to private fields in the custom class so they will always be available, even when using recycler views.
Contrast that with including a layout. In that case, the layout has to define a root element (which can be your custom control, but in that case, you would not inflate the layout into yourself and would have to move the control lookup to onFinishInflate) but otherwise it ends up with the same view hierarchy.
In short, instead of this...
<include layout="#layout/layout_myCustomControl" />
You can now do this...
<com.mydomain.MyCustomControl />
However I find the auto-loading custom control version to be much more flexible and maintainable. The advantages of the second one are not only that you can use custom attributes in the referencing XML layouts (which you can't with the 'include' version) but it also gives you a central place to manage the code as well as layout management/control lookup.
So now I can do this...
<com.mydomain.MyCustomControl
app:myCustomAttribute="Foo" />
And if the control has to have code backing up its behavior, it's nicely encapsulated in the custom view.
Here's an example layout for the auto-loading version...
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is static text in the header" />
<TextView android:id="#+id/dateTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</merge>
And here's the class that uses it...
public class MainHeader extends LinearLayout
{
TextView dateTextView;
public MainHeader(Context context, #Nullable AttributeSet attrs)
{
super(context, attrs);
setOrientation(VERTICAL);
LayoutInflater.from(context).inflate(R.layout.header_main, this);
dateTextView = (TextView)findViewById(R.id.dateTextView);
dateTextView.setText(<<Code for setting date goes here>>);
}
}
But what I'm wondering is if the layout is purely static in nature--say holding a static image and fixed text--is it still considered good practice to use a custom view to represent it? I'd say yes for consistency, plus should I want to extend it in the future, you're already prepared for it and have to do so in just one place regardless of how many places it's used. In contrast, if you included the layout directly in say 20 places, you may have to update all 20 (depending on what's actually changed/needed.)
Pros for the Custom View approach:
Central location for managing layout loading and control lookup
Can support backing code implicitly/internally for updating the view.
Can use attributes when being referenced in other layout files
Better encapsulation (you can hide the layout itself from the outside world exposing behaviors via direct methods)
Can simply be 'new'd' up in code and the layout will automatically load. No inflating or casting needed.
Cons for Custom View approach
When used in Layout files, you now have to also specify width and height making usage a little more verbose.
May add extra classes to your project (not always, but sometimes.)
Again, it seems to me like a no-brainer, but I'm wondering if there's a preferred 'Androidy' way, or is it just a preference up to each developer?
Such approach will add additional level in your view trees. So you only made the UI tree more complex for no good reason. From other side, you can follow next steps to get rid of that side-effect:
<merge /> can only be used as the root tag of an XML layout
when inflating a layout starting with a <merge />, you must specify a parent
ViewGroup and you must set attachToRoot to true (see the
documentation of the inflate() method)
That's it.
Well apparently what I came up with wasn't that unique after all! Here's an article explaining in detail this exact scenario, along with the pros and cons of each. Looks like they too came to the same conclusion.
TrickyAndroid: Protip. Inflating layout for your custom view
inflater.inflate(R.layout.fragmenta , container , false);
We use this line of code for inflating. Despite read documentary , i didn't understand what is the second and third parameters function is ? What is the root in this situation and what happen if i change third to true ?
In your layout XML file some of the attributes relate to the parent container. Anything that starts with layout_*. The container, or parent in some cases, is needed to resolve those values. You can see this with things like layout_margin. If you don't give the inflater a parent you won't have any margins. But if you wrap your layout in another container like a frame layout it works. That's because it's able to resolve layout_margin using the frame layout. I'm not completely sure about the attach to parent boolean. I always get Exceptions when I set it to true.
Layout Inflater
The video should give you a good explanation of what is done and why it is done.
I am using the following layout:
---------------------
FrameLayout
.>>. FrameLayout
.>>. FrameLayout
---------------------
This layout is set on some Activity using setContentView().
I just run lint to analyse my project and got the following message:
MergeRootFrame: FrameLayout can be replaced with <merge> tag
I understand and use the merge element in certain layouts but I fail to understand how can I be advised to merge the root element in my layout when there is no obvious parent to merge with, when I do the correction and run it all goes well but for some reason this feels a bit fishy.
Thanks!
Read the following post by Romain Guy:
http://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/
"the parent of an activity’s content view is always a FrameLayout"
Answered my question q:)
The window provided for your application by the system has a FrameLayout that is the parent for your Activity's view hierarchy.
I have a custom component that actually wraps another component. Its layout is:
<AutoCompleteTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:background="#drawable/text_view_background" android:textCursorDrawable="#null"
android:textColor="#android:color/black" android:inputType="textNoSuggestions"
android:paddingLeft="7dp"/>
In the component's code I'm trying to inflate it:
inflate(context,R.layout.results_auto_complete,this);
resultsAutoComplete=(AutoCompleteTextView)getChildAt(0);
But I'm getting a ClassCastException and it says the first child is a RelativeLayout! I traced all the children of this relative layout and it's actually the layout of the widget whose configuration activity contains my custom component! When I tested the component with a simple test activity everything worked!
So why is it happening and what can I do about this?
Thanks.
If your AutoCompleteTextView is a standalone xml file (your code is the root xml tag) of results_auto_complete.xml. It is the result of the inflation, NO need to use getChildAt(i).
if <AutoCompleteTextView> is a child element in an XML file, use should assign it an Id: android:id="#+id/your_view_id". Then after the inflation, use:
this.findViewById(R.your_view_id);
where this is current activity which loads the component view.
Update, try this:
LayoutInflater mInflater = (LayoutInflater)etContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
resultsAutoComplete=(AutoCompleteTextView)mInflater.inflate(R.layout.your_view_id, this, true);
It seems the problem is that I have 2 layouts with the same identifiers from different projects (one project is linked to the other), so when I'm trying to inflate a layout from one of the projects, I'm getting the layout with the same identifier in the other project. Anyway, thanks for trying to help.
When declaring custom view in xml, what is the difference between declaring a View of a custom class, or declaring a completely custom view:
<LinearLayout>
<view class="packageName.MyView" android:id="#+id/myView" />
</LinearLayout>
and
<LinearLayout>
<packageName.myView android:id="#+id/myView" />
</LinearLayout>
?
I've created a subclass of EditText, and when instatiating it as View class=".." my Activity crashes with ClassCastException when trying to access MyView:
(MyView) myView = (MyView) findViewById(R.id.myView);
When declared as second option, everything works as expected.
I'm not 100% sure on this, but let me give it a go. A couple of things could be happening. The parser might not understand the class attribute correctly (e.g. it thinks it is part of a stylesheet). I am not sure how the parser handles the class attribute, since I have never seen or used it (in fact, I've never seen the <View> tag used either). A better explanation, though, might be this: the parser is trying to down-cast your View into packageName.myView class and fails (down-casting is always risky; up-casting is always safe).
Regardless of what is happening, I would always use the second option you listed, <packageName.myView android:id...>, instead of using the <View> tag. Reason being, it's redundant to use the <View> tag. Everything in this xml file must be a view (LinearLayout, Button, TextView, etc. are all descendants of the View class).
Hope that helps. If you're really, really curious, you could always download the source code for the parser...