Search code examples
javaandroidactionbarsherlockandroid-viewpagerslidingdrawer

SlidingMenu with ViewPager and ActionBarSherlock Tabs


In my calendar application, I am using ActionBarSherlock to display two tabs - 1) Calendar 2) Converter. On the click event of an ActionBar menu item, I'm using SlidingMenu drawer to display event summary for that month.

I want to use viewpager specifically for the Calendar tab and I have implemented it this way:

Main.java:

public class BaseActivity extends SlidingSherlockFragmentActivity 
{

    private ViewPager pager;
    CalendarFragmentPagerAdapter mPagerAdapter;
    private static final int MONTHS_LIMIT = 5;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState); 

        setTitle(R.string.app_name);

        setContentView(R.layout.main);
        getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.main, new CalendarFragment())
        .commit();

        setBehindContentView(R.layout.content_frame);
        getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.content_frame, new EventsSummary())
        .commit();

        setSlidingActionBarEnabled(false);

        final ActionBar bar = getSupportActionBar();
        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        bar.setHomeButtonEnabled(true);

        ActionBar.Tab calendar = bar.newTab();
        ActionBar.Tab converter = bar.newTab();

        calendar.setText(this.getResources().getString(R.string.calendar));
        converter.setText(this.getResources().getString(R.string.converter));

        calendar.setTabListener(new MyTabListener());
        converter.setTabListener(new MyTabListener());

        bar.addTab(calendar);
        bar.addTab(converter);

        // customize the SlidingMenu
        SlidingMenu sm = getSlidingMenu();
        sm.setShadowWidthRes(R.dimen.shadow_width);
        sm.setShadowDrawable(R.drawable.shadow);
        sm.setBehindOffsetRes(R.dimen.actionbar_home_width);
        sm.setSlidingEnabled(false);

        mPagerAdapter = new CalendarFragmentPagerAdapter(getSupportFragmentManager());
        pager = (ViewPager) this.findViewById(R.id.viewpager);
        pager.setAdapter(mPagerAdapter);
        pager.setCurrentItem(MONTHS_LIMIT / 2);


    }


    private class MyTabListener implements ActionBar.TabListener
    {

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            if(tab.getPosition()==0)
            {
                CalendarFragment frag = new CalendarFragment();
                ft.replace(R.id.main, frag);
            }
            else
            {
                ConverterFragment frag = new ConverterFragment();
                ft.replace(R.id.main, frag);
            }
        }
        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            // TODO Auto-generated method stub
        }
        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // TODO Auto-generated method stub
        }
     }

    public boolean onOptionsItemSelected(MenuItem item) {
        Intent newActivity;
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.menu_slidingmenu:
                toggle();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }



    public class CalendarFragmentPagerAdapter extends FragmentPagerAdapter {

        public CalendarFragmentPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            CalendarFragment fragment = new CalendarFragment();
            Bundle args = new Bundle();
            args.putInt("offset", position - MONTHS_LIMIT / 2);
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public int getCount() {
            return MONTHS_LIMIT;
        }

    }
}

CalendarFragment.java:

public class CalendarFragment extends Fragment
{

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            Bundle args = getArguments();
            int offset = args.getInt("offset"); //throws NullPointerException
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

            View v =  inflater.inflate(R.layout.simple_calendar_view, container, false);

            .....

            return v;
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putBoolean("dummy", true);
        }


}

The problem is at this line in the CalendarFragment:

int offset = args.getInt("offset");

It throws the error NullPointerException and debugging shows this is because Bundle args = getArguments() is null.

I tried to put the breakpoint at this line in the PagerAdapter:

Bundle args = new Bundle();

but it never reaches here and the application crashes throwing the NullPointerException.

Where am I going wrong?


Solution

  • Here

    getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.main, new CalendarFragment())
            .commit();
    

    and here

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if (tab.getPosition() == 0) {
            CalendarFragment frag = new CalendarFragment();
            ft.replace(R.id.main, frag);
        } else {
            ConverterFragment frag = new ConverterFragment();
            ft.replace(R.id.main, frag);
        }
    }
    

    you're just creating an empty CalendarFragment instance without any arguments.

    So your activity launches, creating an empty Fragment without arguments, and then crashes when trying to get those