62

I have an include like:

<include
    android:id="@+id/placeHolder"
    layout="@layout/test" />

The include layout looks like (test.xml):

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/outer"
    ... >

    <ImageView
        android:id="@+id/inner"
        ... />
</FrameLayout>

I can't seem to find the inner ImageView with id="inner" at runtime:

ImageView iv = (ImageView)findViewById(R.id.inner);
if (iv == null) {
    Log.e(TAG, "Not found!");
}

Should I be able to find it? It seems like since it's using an "include", the normal findViewById method does not work.

---------- Update ----------------

So I can find the id assigned to the include:

View view = findViewById(R.id.placeHolder); // ok

but I can't find any of its children by id like:

view.findViewById(R.id.outer); // nope
view.findViewById(R.id.inner); // nope

same as the original if I try searching for them directly like:

findViewById(R.id.outer); // nope
findViewById(R.id.inner); // nope

Do ids just get stripped off of elements at runtime maybe?

Thanks

user291701
  • 38,411
  • 72
  • 187
  • 285
  • Sorry, "test.xml", typo, thanks. – user291701 May 29 '12 at 17:12
  • any error if yes then post logcat – Samir Mangroliya May 29 '12 at 17:13
  • Had the same issue. In the end I was referencing my views inside the included layout incorrectly. I was including one of the layout resources that comes with the SDK and therefore had to use `andorid.R.id.` as opposed to `R.id.` in my `findViewById()`. The solution of dymmeh worked fine once I fixed this. – jhavatar Oct 31 '14 at 11:33

9 Answers9

103

Try retrieving the <include /> and then searching within that

Make sure your root has the same ID as the root element in the included XML file.. ex

<include
    android:id="@+id/outer"
    layout="@layout/test" />

Then retrieve your "inner" content using:

FrameLayout outer = (FrameLayout)findViewById(R.id.outer);

ImageView iv = (ImageView)outer.findViewById(R.id.inner);
if (iv == null) {
    Log.e(TAG, "Not found!");
}
dymmeh
  • 22,247
  • 5
  • 53
  • 60
  • 13
    Try out my updated answer. Make sure your id of the include is the same as the root element in your included XML file – dymmeh May 29 '12 at 17:29
  • 2
    If the include's id is the same as the inner's root element, then there is no use overriding it, it will be inflated as-is. According to LayoutInflater source, it won't override the id of a merge root element - making it roughly useless to reuse layouts, which could share id's and let them be overridden when included – Rafael Nobre Jul 23 '13 at 21:38
  • 1
    It is a old post but very useful in nowadays. Very thanks @dymmeh , maybe you could improve your answer adding a comment to be careful when using casting to Android widgets such as FrameLayout. Maybe it obvious, but in my case I had a NPE when I used a casting from FrameLayout to LinearLayout. – e2a Mar 23 '16 at 13:38
  • 7
    I just want to point out the importance of making sure the id of the include is the same as the id of the root element in the included XML file. Exactly as @dymmeh said. The first time I read the answer I completely missed the suggestion, and it is REALLY important to take it into account. Thanks a lot for the help! – blastervla Jun 26 '17 at 20:15
  • for those wondering. Tag `` acts like the parent layout by default, you might wanna cast it into `YourParentLayout` inside the `android:layout="@layout/your_layout"` otherwise `ClassCastException` thrown instead – mochadwi Jan 06 '20 at 09:13
21

I just wanted to add to this for future Googlers, I had kind of the opposite problem where the root layout of the included xml (in this case outer), was null when calling findViewById(), but the children of outer were not null.

The problem was solved for me by removing the id property of the include 'view' (in this case placeHolder). When that was gone, I could find outer but it's id :)

If you need a an id assigned to the include item, I think it's better to wrap it in another viewgroup.

Daniel Wilson
  • 18,838
  • 12
  • 85
  • 135
  • 7
    This worked for me - thanks. I did a little more digging and (at least in my non-fragment code) I found the following: If you have an include with a id and want to access the top level of the included structure then the include id must be the same as the id of the top level structure of the included item. This feels wrong in that it seems to be a duplicate name - bit it works. The other alternative which also works is your solution - i.e. miss out the name on the include. – Richard Apr 28 '15 at 12:57
  • For other googlers you might wanna try calling the `findViewById` in `onViewCreated`, if you're using a fragment :) – nmu Sep 27 '17 at 20:12
  • 1
    For future readers, the `` id will override child layout id, it still work if you `findViewById` with that `` id instead of child layout id, or else will null. The alternative way is what this answer suggested, i.e. remove the `` id and remains only child layout id. And don't forget to change other stuff such as `layout_above` which refer to that `` id if you've added. – 林果皞 Oct 17 '18 at 20:41
  • Thanks, that was my problem) You don't need to look for included layout, you just look for it's child views – chill appreciator Nov 15 '20 at 16:27
1

Future researchers: https://stackoverflow.com/a/1760010/2790016 when you add an id to it overwrites the id from the outer tag from the "real layout"

Given that most constraint layouts need an id to positions items, removing the id from include is not an ideal answer.

Beto
  • 806
  • 3
  • 12
  • 33
1

Don't give your included layout an ID

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@id/twitterItem"
    android:id="@+id/item1">

    <include
        layout="@layout/item_common_layout"/>

</FrameLayout>

item_common_layout

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    ... >

    <ImageView
        android:id="@+id/inner"
        ... />
</FrameLayout>

now you could find inner Views:

ImageView iv = (ImageView) view.findViewById(R.id.inner); // works fine!
Mohamed AbdelraZek
  • 2,503
  • 4
  • 25
  • 36
0

Can you try then finding the outer parent (lets call it op) and then try op.findViewById()?

Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
Felipe Caldas
  • 2,492
  • 3
  • 36
  • 55
0

I had the same problem. I found out that I used a wrong function with the same name with 2 parameters as following:

public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
    super.onCreate(savedInstanceState, persistentState);
    setContentView(R.layout.activity_ble_connecting);
    //findViewByid() => wrong
} 

correct function with only one parameters:

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ble_connecting);
        //findViewByid() => correct
    }
HungNM2
  • 3,101
  • 1
  • 30
  • 21
0

If you have given the id to the include element and you have only single view in the included layout (not in any ViewGroup), in my case AdView, then use the id of include element instead of included view.

<?xml version="1.0" encoding="utf-8"?>
<!--adview.xml-->
<com.google.android.gms.ads.AdView
        xmlns:ads="http://schemas.android.com/apk/res-auto"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/adView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        ads:adSize="BANNER"
        ads:adUnitId="@string/admob_banner_id">
</com.google.android.gms.ads.AdView>

activity_main.xml

<include
        layout="@layout/adview"
        android:id="@+id/adsLayout"
  />

In activity

AdView nullAdView=findViewById(R.id.adView); //this will give null
AdView adView = findViewById(R.id.adsLayout);  //this will be AdView

If you do not give id to include element then it is ok to use view id. Also if your view is inside any ViewGroup like FrameLayout then it is ok to use view id.

0

I found the answer to this problem.

This problem arises when we set both the Incloud ID and the first inner layer.

I used merge to solve the problem.

 <include
    android:id="@+id/layout_stories"
    layout="@layout/layout_stories" />

and in layout_stories

<merge>
<LinearLayout
android:id="@+id/llItem">
 ...
</LinearLayout>
<merge>
saeedmpt
  • 144
  • 1
  • 7
0

I followed Daniel Wilson's answer and got the solution. I was using the same layout multiple times in same screen and wanted to refer them using different id. So, instead of assigning id to the include tag, I simply wrapped them in another viewGroup (I used FrameLayout) and id'ed the frameLayout to access the inner children. That worked succesfully. Example:

In my main.xml:

<!--    ITEM 1-->
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@id/twitterItem"
    android:id="@+id/item1">

    <include
        layout="@layout/item_common_layout"/>

</FrameLayout>

<!--    ITEM 2-->
<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@id/item1"
    android:id="@+id/item2">

    <include
        layout="@layout/item_common_layout"/>

</FrameLayout>