Issue
I develops an Android Application and I'm facing some problems.
In my MainActivity
I have the following components:
- Navigation Drawer (instanciates and loads many fragments)
- ViewPager (only for
ArticleFragment
which display the detail view of an article)
Normaly, the ViewPager is related to a specific Activity, but I really want to use both Navigation Drawer and ViewPager. The only way is to implement both elements in same activity.
The DrawerLayout
is composed by the navigation drawer itself and by the content area. In my content area I have a FrameLayout
and the ViewPager
. The problem is that the ViewPager
is always displayed.
So my idea was to play with the android:visibility
property to show/hide alternately the FrameLayout and the ViewPager. If you look at my activity_main.xml
you can notice the android:visibility
set to invisible
on the ViewPager
.
/layout/activity_main.xml
<!-- The main content view -->
<RelativeLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/container"
android:paddingTop="?android:attr/actionBarSize"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- ViewPager -->
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</RelativeLayout>
<!-- The navigation drawer -->
<fragment android:id="@+id/navigation_drawer"
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
android:name="NavigationDrawerFragment" />
</android.support.v4.widget.DrawerLayout>
And then:
MainActivity.java
public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private NavigationDrawerFragment mNavigationDrawerFragment;
private FrameLayout mContainer;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the navigation drawer
mContainer = (FrameLayout) findViewById(R.id.container);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout));
// Set up the viewpager
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
}
//-------------------------------//
// NAVIGATION DRAWER //
//-------------------------------//
/**
* Update the main content by replacing fragments
*/
@Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment = null;
Boolean viewPagerArticles = false;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new FooFragment();
break;
case 2:
viewPagerArticles = true;
// Hide navigation drawer container and show the viewpager
mContainer.setVisibility(FrameLayout.GONE);
mPager.setVisibility(ViewPager.VISIBLE);
// NullPointerException with new this line. Why?
// Fragment already instanciate in ScreenSlidePagerAdapter -> getItem() -> ArticleFragment.create()?
//fragment = new ArticleFragment();
break;
default:
break;
}
// Show the view pager and hide navigation drawer container
// =================
// THE BUG IS HERE
// =================
if (!viewPagerArticles) {
mContainer.setVisibility(FrameLayout.VISIBLE);
mPager.setVisibility(ViewPager.GONE);
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
}
...
//-------------------------------//
// VIEWPAGER //
//-------------------------------//
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
public ScreenSlidePagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return DayFragment.create(position);
}
@Override
public int getCount() { ... }
}
...
}
NavigationDrawerFragment.java
Display ViewPager content
On my HomeFragment
I have a button with a onClickListener:
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((MainActivity)getActivity()).onNavigationDrawerItemSelected(2);
}
});
When I load MainActivity I have these errors : InflateException and NullPointerException
AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android/com.example.android.ui.MainActivity}: android.view.InflateException: Binary XML file line #34: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #34: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:267)
at android.app.Activity.setContentView(Activity.java:1895)
at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:216)
at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:111)
at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76)
at com.example.android.ui.MainActivity.onCreate(MainActivity.java:42)
at android.app.Activity.performCreate(Activity.java:5133)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.example.android.ui.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:117)
at com.example.android.ui.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:202)
at com.example.android.ui.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:80)
at android.support.v4.app.Fragment.performCreate(Fragment.java:1477)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:893)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082)
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1184)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:291)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:267)
at android.app.Activity.setContentView(Activity.java:1895)
at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:216)
at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:111)
at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76)
at com.example.android.ui.MainActivity.onCreate(MainActivity.java:42)
at android.app.Activity.performCreate(Activity.java:5133)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
at android.app.ActivityThread.access$600(ActivityThread.java:141)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Everything is fine (no errors, activity loaded) without:
// =================
// THE BUG IS HERE
// =================
if (!viewPagerArticles) {
mContainer.setVisibility(FrameLayout.VISIBLE);
mPager.setVisibility(ViewPager.GONE);
}
...but it does not match my expectations because the Navigation Drawer fragments are always hiding (it's normal because of mContainer.setVisibility(FrameLayout.GONE);
. I just want to inverse the mContainer/mPager visibilities.
I hope I was enough clear...!
Any idea?
Solution
You get that NullPointerException
because the of the way you built the NavigationDrawerFragment
fragment. More precisely, in its onCreate()
method you call selectItem()
which propagates through the Activity
(registered as a listener) to the onNavigationDrawerItemSelected()
callback. The problem is that the fragment will be inflated at the point when setContentView()
is called(in onCreate()
) which means you'll enter the onNavigationDrawerItemSelected()
callback before the lines:
mContainer = (FrameLayout) findViewById(R.id.container);
mPager = (ViewPager) findViewById(R.id.pager);
run, rendering those references null
in onNavigationDrawerItemSelected()
.
To solve this you could simply replace the current <fragment />
tag from the Activity
layout with a basic container(a placeholder empty FrameLayout
for example) and add the NavigationDrawerFragment
manually in onCreate()
after the lines above(where you bind the views). There could be another better solution(or I could make other suggestions) but it's not very clear how you want to handle the visibility. Maybe you can expand on this.
Edit 2:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the navigation drawer
mContainer = (FrameLayout) findViewById(R.id.container);
// Set up the viewpager
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
if (savedInstanceState == null) {
NavigationDrawerFragment ndf = new NavigationDrawerFragment();
ndf.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout));
getSupportFragmentManager().beginTransaction().add(R.id.nav_drawer, ndf).commit();
}
}
Edit 1:
//...
<!-- ViewPager -->
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</RelativeLayout>
<!-- The navigation drawer -->
<FrameLayout android:id="@+id/nav_drawer"
android:layout_width="@dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
/>
</android.support.v4.widget.DrawerLayout>
And in onCreate()
at the end:
//...
mPager.setAdapter(mPagerAdapter);
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
getSupportFragmentManager().beginTransaction().add(R.id.nav_drawer, new NavigationDrawerFragment()).commit();
If you get an exception with the code above, it's in the same onNavigationDrawerItemSelected()
method?
Answered By - user
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.