Does Android XML Layout's 'include' Tag Really Work?

AndroidAndroid Widget

Android Problem Overview


I am unable to override attributes when using <include> in my Android layout files. When I searched for bugs, I found Declined Issue 2863:

"include tag is broken (overriding layout params never works)"

Since Romain indicates this works in the test suites and his examples, I must be doing something wrong.

My project is organized like this:

res/layout
  buttons.xml

res/layout-land
  receipt.xml

res/layout-port
  receipt.xml

The buttons.xml contains something like this:

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

  <Button .../>

  <Button .../>
</LinearLayout>

And the portrait and landscape receipt.xml files look something like:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

  ...

  <!-- Overridden attributes never work. Nor do attributes like
       the red background, which is specified here. -->
  <include
      android:id="@+id/buttons_override"
      android:background="#ff0000"
      android:layout_width="fill_parent"
      layout="@layout/buttons"/>

</LinearLayout>

What am I missing?

Android Solutions


Solution 1 - Android

I just found the issue. First, you can only override layout_* attributes, so the background won't work. That is documented behavior and simply an oversight on my part.

The real problem is found in LayoutInflater.java:

// We try to load the layout params set in the <include /> tag. If
// they don't exist, we will rely on the layout params set in the
// included XML file.
// During a layoutparams generation, a runtime exception is thrown
// if either layout_width or layout_height is missing. We catch
// this exception and set localParams accordingly: true means we
// successfully loaded layout params from the <include /> tag,
// false means we need to rely on the included layout params.
ViewGroup.LayoutParams params = null;
try {
   params = group.generateLayoutParams(attrs);
} catch (RuntimeException e) {
   params = group.generateLayoutParams(childAttrs);
} finally {
   if (params != null) {
     view.setLayoutParams(params);
   }
}

If the <include> tag does not include both layout_width and layout_height, the RuntimeException occurs and is silently handled, without any log statement even.

The solution is to always include both layout_width and layout_height when using the <include> tag, if you want to override any of the layout_* attributes.

My example should change to:

<include
      android:id="@+id/buttons_override"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      layout="@layout/buttons"/>

Solution 2 - Android

I submitted an enhancement request to allow all included attributes to be overridden:

> Suppose I have two identical layouts other than the values of a > TextView field. Presently, I either have modify the layout at > runtime or duplicate the XML. > > For example to pass two parameters with values "hello" and "world" to layout1: > > <include layout="@layout/layout1a" > params="textView=hello|editText=world" /> > > layout1a.xml: > > <merge><TextView text="@param/textView"><EditText > hint="@param/editText"></merge> > > An alternate implementation would break encapsulation and would allow > the include statement to override values like: > > <include layout="@layout/layout1b" > overrides="@id/textView.text=hello|@id/editText.hint=world" /> > > layout1b.xml: > > <merge><TextView id="@+id/textView"><EditText > hint="@+id/editText"></merge>

Solution 3 - Android

I found I sometimes miss including the android:id tag when using the GUI builder in Eclipse. Making sure (when I notice) that I add into a TextView from the builder , the id I'm using in the ListView layout.

<TextView android:text="@+id/textView1"
		android:layout_width="wrap_content" 
		android:layout_height="wrap_content" />
...

becomes

<TextView android:id="@+id/textView1"
		android:layout_width="wrap_content" 
		android:layout_height="wrap_content" />
...

Instead of getting 'false' 'false' I get :) and includes working ok.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric BurkeView Question on Stackoverflow
Solution 1 - AndroidEric BurkeView Answer on Stackoverflow
Solution 2 - AndroidJeff AxelrodView Answer on Stackoverflow
Solution 3 - AndroidTheSolarSheriffView Answer on Stackoverflow