29

I have been using the v23.0.1 support library until now with no problems. Now when I switch to the new v23.1.0 library I am getting a null pointer on widgets in the drawer layout.

mNavigationView = (NavigationView) findViewById(R.id.navigation_view);    
TextView username = (TextView) mNavigationView.findViewById(R.id.username_textView);
//       ^^^^^^^^ is now null when using new library
// which causes the following to fail
username.setText(mUser.getName());

activity layout

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

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

    ...

</LinearLayout>

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/drawer_header"
    app:menu="@menu/drawer_items" />

</android.support.v4.widget.DrawerLayout>

drawer_header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="150dp"
android:orientation="vertical">

   <TextView
    android:id="@+id/username_textView"
    android:layout_width="match_parent"
    android:layout_height="0dp" />

    ...

</LinearLayout>

Simply changing the gradle file to use the older version makes it work fine instantly so I don't think there is anything horribly wrong with my code. I checked out the revisions in the update and didn't see anything that I would think to cause this.

Surely this will be affecting others also, any clues?

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Breavyn
  • 2,232
  • 16
  • 29

5 Answers5

41

With the design library v 23.1.0 the NavigationView works with a RecyclerView.
Also the Header is now a type of row.

It means that the header could not be immediately available in the view hierarchy.
It can cause issues if you are using methods like navigationView.findViewById(XXX) to get a view inside the header.

There is a bug in the Google Tracker.

EDIT 12/10/2015: Design library 23.1.1

The 23.1.1 introduces a new API for retrieving header views for NavigationView with getHeaderView()

BEFORE 23.1.1

workaround fot 23.1.0 can be to use a addOnLayoutChangeListener. Somenthing like:

navigationView.addOnLayoutChangeListener( new View.OnLayoutChangeListener()
{
    @Override
    public void onLayoutChange( ... )
    {
        navigationView.removeOnLayoutChangeListener( this );

        View view = navigationView.findViewById( ... );
    }
} );

Another possible workaround are:

  • remove the app:headerLayout attribute from the xml, and then add the header programatically.

  • Inflate the headerView programmatically.

Use somenthing like this:

View headerLayout = navigationView.inflateHeaderView(R.layout.navigation_header);
headerLayout.findViewById(xxx);
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 4
    `NavigationView` has the methods `addHeaderView()` `inflateHeaderView()` and `removeHeaderView()`. Perhaps they should give us a `getHeaderView()` method as well that works when creating from xml. – Breavyn Oct 16 '15 at 06:21
  • Good answer. This is exactly how I got headers working last week when 23.1 came out. I was so excited about some of the other fixes in 23.1, but then I ran into this new problem. The only way to get around it for now is to inflate in code. – hungryghost Oct 23 '15 at 04:05
  • @ColinGillespie Sir, `inflateHeaderView()` is already taking integer resource as argument and it returns `View` object. Now using this `View` object, we can find our inner Views or controls and save it for future use.. Say, for example, updating the profile pic in `NavigationView`.. – Chintan Soni Nov 16 '15 at 05:59
  • @ChintanSoni Yes I release this; as can be seen in this answer and my answer below. The point is to be able to access a header view that was added purely from xml using the `app:headerLayout=""` option. – Breavyn Nov 16 '15 at 08:49
11

It appears attaching the header view to the navigation drawer using xml is currently broken. The solution is to inflate and attach the view manually.

activity layout

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/drawer_header" <!-- remove this line -->
    app:menu="@menu/drawer_items" />

Then in your code inflate and attach the header by doing the following.

NavigationView navigationView = (NavigationView) findViewById(R.id.navigation_view);
View drawerHeader = navigationView.inflateHeaderView(R.layout.drawer_header);

TextView username = (TextView) drawerHeader.findViewById(R.id.username_textView);
Breavyn
  • 2,232
  • 16
  • 29
0

in the new NavigationView the header is now a row type of RecyclerView in order for you or anybody to find the view by its id you'll need to workaround it and use addOnLayoutChangeListener listener and then you can find the view i know it should be documented somewhere but android be like meh!.

Kosh
  • 6,140
  • 3
  • 36
  • 67
  • Alright that makes sense. Is it preferable to use this workaround or the one I described? Or it doesn't really matter? – Breavyn Oct 16 '15 at 03:44
  • i haven't tried your workaround tho, as you stated that the xml is currently broken but this seems to solve it. so both of them should be acceptable as its now more to personal choice, whether define it from xml or programmatically. – Kosh Oct 16 '15 at 04:03
0

it is a bug at 23.1.0

23.1.1 fixed

https://plus.google.com/+AndroidDevelopers/posts/ebXLByBiEBU

xushao
  • 93
  • 1
  • 2
0

I have updated build tools from Android sdk manager, then 23.1.0 is also working fine for me.

I am using

buildToolsVersion "23.0.2"

before this it was 23.0.1.

and there is no need of using

(View)navigationView.findViewById(R.id.idOfViewFromHeaderView);

In your activity you can directly use

(View)findViewById(R.id.idOfViewFromHeaderView);
Muhammad Adil
  • 4,358
  • 3
  • 32
  • 36