1

I have implemented Navigation drawer given in the Android Studio 1.5.1.

  • I have 5 navigation drawer items with a fragment to each of them. Each Fragment has Share method (Not common).
  • Inside 1st Navigation drawer item's fragment lets say OldStory Fragment, I am having Swipe view with Viewpager consisting 3 fragments with FragmentStatePagerAdapter. It has Share method.

Problem - Share Method from Story Fragment is getting called every time even when other fragment is shown on screen. After debugging I came to know that method from Story fragment is getting called. - If I disable OldStory Fragment then everything works fine.

I am unable to solve this problem. I read so many Question/answers but they are related to Activity and Fragment methods. Please help me to solve this problem.

Note - OldStory fragment has inner class that extends FragmentStatePagerAdapter class. This class creates Many Story Fragments. Other implementation is same.

public class OldStory extends Fragment {

private StoryPagerAdapter storyPagerAdapter;
private InfiniteViewPager viewPager;
SharedPreferences sharedPreferences;
private int TotalCount;

public OldStory() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Notify the system to allow an options menu for this fragment.

}



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    final View rootView = inflater.inflate(R.layout.fragment_old_story, container, false);
    viewPager = (InfiniteViewPager) rootView.findViewById(R.id.pager);
    viewPager.setOffscreenPageLimit(0);
    sharedPreferences = getActivity().getSharedPreferences(Startup.PreferenceSETTINGS, Context.MODE_PRIVATE);
    TotalCount = sharedPreferences.getInt(Startup.StoryCount, 4);
    storyPagerAdapter = new StoryPagerAdapter(getFragmentManager());
    PagerAdapter wrappedAdapter = new InfinitePagerAdapter(storyPagerAdapter);
    viewPager.setAdapter(wrappedAdapter);
    viewPager.setCurrentItem(TotalCount-1);

    return rootView;
}

public class StoryPagerAdapter extends FragmentStatePagerAdapter {
    public StoryPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {

        return Story.newInstance(position+1);
    }

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

Story Fragment method Implementation -

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    menu.clear();
    inflater.inflate(R.menu.story, menu);
    getActivity().getMenuInflater().inflate(R.menu.main, menu);
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.Refresh:
            // We make sure that the SwipeRefreshLayout is displaying it's refreshing indicator
            if(!visiblity) {
                if (!RefreshLayout.isRefreshing()) {
                    ErrorLayout.setVisibility(View.GONE);
                    RefreshLayout.setRefreshing(true);
                }

                // Start our refresh background task
                initiateRequest(Today);
            }
            return true;

        case R.id.Share:
            //InShort = sharedPreferences.getString(Startup.InShort, null);
            Toast.makeText(getContext(), "Stories", Toast.LENGTH_SHORT).show();
            if (InShort!= null && !InShort.isEmpty())
            {

                Intent sendIntent = new Intent(Intent.ACTION_SEND);
                sendIntent.putExtra(Intent.EXTRA_TEXT, "Hi From Story");
                sendIntent.setType("text/plain");
                startActivity(sendIntent);
            }

            return true;

        default:
            return super.onOptionsItemSelected(item);
    }


}

MainActivity used for switching fragments.

public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    displayView(item.getItemId());

    return true;
}

//method to replace Views in ID = content_frame in content_main
public void displayView(int viewID)
{
    fragment = null;
    title = getString(R.string.app_name);

    switch (viewID)
    {
        case R.id.nav_frag0:
            fragment = new OldStory();
            title = getString(R.string.story);
            viewIsAtHome = true;
            break;

        case R.id.nav_frag1:
            fragment = new Fragment1();
            title = getString(R.string.fragment1);
            viewIsAtHome = false;
            break;

        case R.id.nav_frag2:
            fragment = new Fragment2();
            title = getString(R.string.fragment2);
            viewIsAtHome = false;
            break;

        case R.id.nav_frag3:
            fragment = new Fragment3();
            title = getString(R.string.fragment3);
            viewIsAtHome = false;
            break;

        case R.id.nav_frag4:
            fragment = new Fragment4();
            viewIsAtHome = false;
            title = getString(R.string.fragment4);
            break;

        case R.id.nav_share:
            fragment = new Fragment5();
            title = getString(R.string.fragment5);
            viewIsAtHome = false;
            break;

    }

    if (fragment != null)
    {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.content_frame,fragment);
        ft.commit();
    }

    //set the toolbar title
    if(getSupportActionBar() != null)
    {
        getSupportActionBar().setTitle(title);
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
}
Roon13
  • 387
  • 2
  • 23
  • Can you add code of how you initialize & switch fragments? Am I right, that the problem is the once you switch through the NavigationDrawer to another fragment, nested in ViewPager fragments still get `onOptionsItemSelected` calls? – Konstantin Loginov Dec 25 '15 at 21:37
  • So far, it looks like you facing same issue, as here: http://stackoverflow.com/a/34401646/1658267 Though, it'd be nice to have more context to be sure – Konstantin Loginov Dec 25 '15 at 21:54
  • And one more thing - how you work with `setHasOptionsMenu()`? – Konstantin Loginov Dec 25 '15 at 22:14
  • @KonstantinLoginov I have updated my question with MainActivity code. – Roon13 Dec 26 '15 at 15:32
  • without setHasOptionsMenu() you'd never get menu be inflated. But in the code snippets, I don't see this method been called. If you want, I can upload the test project with viewpagers, different fragments and NavigationDrawer, so you can try to see the possible difference.. – Konstantin Loginov Dec 26 '15 at 15:43
  • Ok, posted my findings around your question below. I hope, I understood your question correctly. – Konstantin Loginov Dec 26 '15 at 16:08
  • I had the same problem. I see a problem in your code `new OldStory();` This will make new fragment everytime you click on the NavigationDrawer item. PS: I cannot post code now as I am browsing your question through SO Mobile App. – zackygaurav Dec 28 '15 at 19:50

2 Answers2

3

I am not sure if it is really the answer to your question, but I noticed one error in your code:

storyPagerAdapter = new StoryPagerAdapter(getFragmentManager());

will not work correctly becasuse you need to use getChildFragmentManager() to manage fragments within fragments.

Rediska
  • 1,392
  • 10
  • 14
1

I was trying to reproduce your issue and wrote this app, which as I understood from the question is copying your app's behaviour:

enter image description here

I've uploaded the source code for it into my Dropbox - feel free to check it out

As you can see, the fragments handle Share button clicks properly. There's always a chance, that I didn't fully understand your question, but here's how I've done it:

All fragments inflating this menu (but with different onOptionsItemSelected):

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/nav_share"
        android:icon="@drawable/ic_menu_share"
        app:showAsAction="always"
        android:title="Share" />
</menu>

My SubFragment class (the one I'm using inside ViewPager) in FragmentA:

public class SubFragment extends Fragment {

    String msg;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.subfragmnet, container, false);
        setHasOptionsMenu(true);
        rootView.findViewById(R.id.subfragmentFrameLayout).setBackgroundColor(getArguments().getInt("background"));
        msg = getArguments().getString("msg");
        return rootView;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_fragment, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.nav_share) {
            Snackbar.make(getView(), "Hello from SubFragment " + msg, Snackbar.LENGTH_LONG).show();
        }

        return super.onOptionsItemSelected(item);
    }
}

FragmentA, the first Fragment, which hosts ViewPager and nested Fragments:

public class FragmentA extends Fragment {

    PagerAdapter pagerAdapter;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_a, container, false);

        Bundle bundle1 = new Bundle();
        bundle1.putInt("background", Color.RED);
        bundle1.putString("msg", "page 1");

        Bundle bundle2 = new Bundle();
        bundle2.putInt("background", Color.YELLOW);
        bundle2.putString("msg", "page 2");

        Bundle bundle3 = new Bundle();
        bundle3.putInt("background", Color.BLUE);
        bundle3.putString("msg", "page 3");

        Fragment[] fragments = {
                Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle1),
                Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle2),
                Fragment.instantiate(getContext(), SubFragment.class.getName(), bundle3),
        };

        if (pagerAdapter == null) {
            pagerAdapter = new PagerAdapter(getChildFragmentManager(), fragments);
        }

        ViewPager viewPager = (ViewPager)rootView.findViewById(R.id.viewPager);
        viewPager.setAdapter(pagerAdapter);

        return rootView;
    }
}

FragmentB (and pretty much the same FragmentC):

public class FragmentB extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        setHasOptionsMenu(true);
        return inflater.inflate(R.layout.fragment_b, container, false);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_fragment, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.nav_share) {
            Toast.makeText(getContext(), "Hello from Fragment B", Toast.LENGTH_LONG).show();
        }

        return super.onOptionsItemSelected(item);
    }
}

Hosting Activity is standard NavigationDrawer Activity with is switching Fragments on Drawer's item click.

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

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

        ....

        getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentA.class.getName())).commit();
    }

    ...

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentA.class.getName())).commit();
        } else if (id == R.id.nav_gallery) {
            getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentB.class.getName())).commit();
        } else if (id == R.id.nav_slideshow) {
            getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, FragmentC.class.getName())).commit();
        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
}

Let me know, if I understood your question properly!

Anyway, I hope, it helps.

Konstantin Loginov
  • 15,802
  • 5
  • 58
  • 95
  • Actually exact problem along with this problem is here : http://stackoverflow.com/questions/34349728/duplicate-menu-and-data-in-fragments-after-using-fragmentstatepageradapter – Roon13 Dec 26 '15 at 18:22
  • @Roon13 I don't get it. There's no menu duplication in my example? (even if I change my `PagerAdapter` from `FragmentPagerAdapter` to `FragmentStatePagerAdapter`) – Konstantin Loginov Dec 26 '15 at 18:31
  • Ya but i am having that problem with same implementation. Thats why it is difficult for me to understand. – Roon13 Dec 26 '15 at 18:41
  • @Roon13 you can browse my code - it's pretty straightforward, so you can use it as a guide. From what I see, for example, you are inflating twice in StoryFragment, while I'm doing it only once. – Konstantin Loginov Dec 26 '15 at 18:45
  • I am inflating StoryFragment just once. Can you point it out if i missed it somewhere?? – Roon13 Dec 26 '15 at 19:01
  • @Roon13 I meant, inflater.inflate(); and then getActivity().getMenuInflater().inflate() looks suspension. If you need some "global" Activity menu - you should inflate it in Activity itself. (It might not solve all problems, but at least it will make code cleaner) – Konstantin Loginov Dec 26 '15 at 19:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99025/discussion-between-roon13-and-konstantin-loginov). – Roon13 Dec 26 '15 at 19:10
  • Thanks for your valuable time. Thanks for pointing out UX flaw. Using list now. Sorry for late reply. – Roon13 Jan 25 '16 at 20:17
  • @Roon13 you're more than welcome. I'm glad, that you nailed it :-) – Konstantin Loginov Jan 25 '16 at 20:39
  • will you help me with this [question](http://stackoverflow.com/questions/35172427/local-notification-is-not-showing-working) ? – Roon13 Feb 03 '16 at 09:28
  • @Roon13 I'll take a look :-) – Konstantin Loginov Feb 03 '16 at 09:44