Abdulrahman Abdulkarim Abdulrahman Abdulkarim - 17 days ago 6
Android Question

App crashing at start after adding navigation drawer

So I'm trying upgrade my

app
by adding the
app drawer
and including a few more pages to the
app
, everything looks fine but the
app
crashes at start, I got the idea from Androidhive.info.The error is regarding the measurements of the
appDrawer
. Attached are the error message, the
MainActivity.java
and the
activity_main.xml
files.
The error message

E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY.
at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:1046)
at android.view.View.measure(View.java:15609)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4916)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:135)
at android.view.View.measure(View.java:15609)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4916)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1411)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:698)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:15609)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4916)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.view.View.measure(View.java:15609)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4916)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1411)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:698)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:15609)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4916)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2191)
at android.view.View.measure(View.java:15609)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2165)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1249)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1443)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1139)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4879)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:776)
at android.view.Choreographer.doCallbacks(Choreographer.java:579)
at android.view.Choreographer.doFrame(Choreographer.java:548)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:762)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:5297)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)


The
MainActivity.java


package com.example.abdulkarim.justjava.activity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.example.abdulkarim.justjava.R;
import com.example.abdulkarim.justjava.fragment.HomeFragment;
import com.example.abdulkarim.justjava.fragment.OrderFragment;
import com.example.abdulkarim.justjava.fragment.SettingsFragment;
import com.example.abdulkarim.justjava.other.CircleTransform;


public class MainActivity extends AppCompatActivity {
private NavigationView navigationView;
private DrawerLayout drawer;
private View navHeader;
private ImageView imgNavHeaderBg, imgProfile;
private TextView txtName, txtWebsite;
private Toolbar toolbar;
private FloatingActionButton fab;

// urls to find load navigation header background image
//and profile image
private static final String urlNavHeaderBg = "http://api.androidhive.info/images/nav-menu-header-bg.jpg";
private static final String urlProfileImg = "https://lh3.googleusercontent.com/eCtE_G34M9ygdkmOpYvCag1vBARCmZwnVS6rS5t4JLzJ6QgQSBquM0nuTsCpLhYbKljoyS-txg";

//index to identify current nav menu item
public static int navItemIndex = 0;

//tags used to attach the fragments
private static final String TAG_HOME = "home";
private static final String TAG_ORDER = "order";
private static final String TAG_SETTINGS = "preferences";
public static String CURRENT_TAG = TAG_HOME;

//toolbar titles respected to selected nav menu item
private String[] activityTitles;

// flag to load home fragment when user presses back key
private boolean shouldLoadHomeFragOnBackPress = true;
private Handler mHandler;



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

mHandler = new Handler();

drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navigationView = (NavigationView) findViewById(R.id.nav_view);
fab = (FloatingActionButton) findViewById(R.id.fab);

//Navigation view header
navHeader = navigationView.getHeaderView(0);
txtName = (TextView) navHeader.findViewById(R.id.input_name);
txtWebsite = (TextView) navHeader.findViewById(R.id.website);
imgNavHeaderBg = (ImageView) navHeader.findViewById(R.id.img_header_bg);
imgProfile = (ImageView) navHeader.findViewById(R.id.img_profile);

//load toolbar titles from string resources
activityTitles = getResources().getStringArray(R.array.nave_item_activity_titles);

fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Text", Snackbar.LENGTH_LONG).setAction("Action", null).show();
}
});

// load nav menu header data
loadNavHeader();

// initializing navigation menu
setUpNavigationView();

if (savedInstanceState == null) {
navItemIndex = 0;
CURRENT_TAG = TAG_HOME;
loadHomeFragment();
}

}

/**
* Load navigation menu header information
* like background image, profile image name,
* website, notifications action view (dot)
*/
private void loadNavHeader() {
// name, website
txtName.setText("Abdulrahman Abdulkarim");
txtWebsite.setText("www.shukura.com");

//loading header background image
Glide.with(this).load(urlNavHeaderBg)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imgNavHeaderBg);
// loading profile image
Glide.with(this).load(urlProfileImg)
.crossFade()
.thumbnail(0.5f)
.bitmapTransform(new CircleTransform(this))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imgProfile);

// showing dot next to notification label
navigationView.getMenu().getItem(3).setActionView(R.layout.menu_dot);
}

/**
* Returns respected fragment that user selected from
* navigation menu
*/
private void loadHomeFragment() {
//selecting appropriate nav menu item
selectNavMenu();

//set toolbar title
setToolbarTitle();

//if user select the current navigation menu again, don't do anything
//just close the navigation drawer
if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
drawer.closeDrawers();

//show or hide the fab
toggleFab();
return;
}

//Sometimes, when fragment has huge data, screen seems hanging
//when switching between navigation menus
//So using runnable, the fragment is loaded with cross fade effect
//This effect can be seen in GMail app
Runnable mPendingRunnable = new Runnable() {
@Override
public void run() {
//update the main content by replacing fragments
Fragment fragment = getHomeFragment();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,
android.R.anim.fade_out);
fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
fragmentTransaction.commitAllowingStateLoss();
}
};

//if mPendingRunnable is not null, then add to the message queue
if (mPendingRunnable != null) {
mHandler.post(mPendingRunnable);
}

//show or hide the fab
toggleFab();

//closing drawer on item click
drawer.closeDrawers();

//refresh toolbar menu
invalidateOptionsMenu();
}

private Fragment getHomeFragment() {
switch (navItemIndex) {
case 0:
//home
HomeFragment homeFragment = new HomeFragment();
return homeFragment;
case 1:
//order
OrderFragment orderFragment = new OrderFragment();
return orderFragment;
case 2:
SettingsFragment settingsFragment = new SettingsFragment();
return settingsFragment;
default:
return new HomeFragment();
}
}

private void setToolbarTitle() {
getSupportActionBar().setTitle(activityTitles[navItemIndex]);
}

private void selectNavMenu() {
navigationView.getMenu().getItem(navItemIndex).setChecked(true);
}

private void setUpNavigationView() {
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {

//This method will trigger on item click of Navigation menu
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {

//Check to see which item was being clicked and perform appropriate action
switch (menuItem.getItemId()) {
//Replacing the main conten with Content Fragment which is our Inbox view
case R.id.nav_home:
navItemIndex = 0;
CURRENT_TAG = TAG_HOME;
break;
case R.id.nav_order:
navItemIndex = 1;
CURRENT_TAG = TAG_ORDER;
break;
case R.id.nav_settings:
navItemIndex = 2;
CURRENT_TAG = TAG_SETTINGS;
break;
case R.id.nav_about_us:
startActivity(new Intent(MainActivity.this, AboutUs.class));
drawer.closeDrawers();
return true;
case R.id.nav_contact:
startActivity(new Intent(MainActivity.this, ContactUs.class));
drawer.closeDrawers();
return true;
default:
navItemIndex = 0;
}

//Checking if the tiem is in checked state or not, if not check the item
if (menuItem.isChecked()) {
menuItem.setChecked(false);
} else {
menuItem.setChecked(true);
}
menuItem.setChecked(true);

loadHomeFragment();

return true;
}
});

ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDraer) {
@Override
public void onDrawerClosed(View drawerView) {
//Code here will be triggered once the drawer closes as we don't want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}

@Override
public void onDrawerOpened(View drawerView) {
//Code here will be triggered once the drawer closes as we don't want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};

//Setting the actionbarToggle to drawer layout
drawer.setDrawerListener(actionBarDrawerToggle);

//calling sync state is necessary or else your hamburger icon won't show up
actionBarDrawerToggle.syncState();
}

@Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawers();
return;
}

//This code loads home fragment when back key is pressed
//when useer is in other fragment than home

if (shouldLoadHomeFragOnBackPress) {
//checking if useer is on other navigation menu
//rather than home
if (navItemIndex != 0) {
navItemIndex = 0;
CURRENT_TAG = TAG_HOME;
loadHomeFragment();
;
return;
}
}

super.onBackPressed();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
//Inflate the menu; this adds items to the action bar if it is present

//show menu only when home fragment is selected
if (navItemIndex == 0) {
getMenuInflater().inflate(R.menu.main, menu);
}
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. the actionbar will
//automatically handle clicks on the Home/Up button, so long
//as you specify a parent activity in AndroidManifest.xml.
return super.onOptionsItemSelected(item);
}

//show or hide the fab
private void toggleFab() {
if (navItemIndex == 0)
fab.show();
else
fab.hide();
;
}

}


activity_main.xml

<?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="fill_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
layout="@layout/app_bar_man"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"/>
</android.support.v4.widget.DrawerLayout>

Answer

You are getting a null pointer exception in the loadNavHeader() method. Can you double check that you are instantiating all the variables in that method correctly in OnCreate().

Would be worth posting your @layout/nav_header_main layout as well.

Comments