1

I've been playing with the com.example.android.common/view/SlidingTabLayout examples, and have hit a minor issue. I know how to work around / resolve it but am trying to understand the issue.

I've created a little app with half a dozen tabs, that displays wot I want, and generally it behaves as expected, but if I RAPIDLY navigate between the tabs, by pressing the tab titles, then I hit the Back button a new tab title View is created and attached to mTabStrip in populateTabStrip(), resulting in a stack of tab titles. The issue only happens if the navigation is Rapid, hit the tab's in a leisurely manner and the issue doesn't crop up, so assuming it's garbage collection related, see below. Anyway was wondering if anyone can explain what is going on behind the scenes.

enter image description here

from SlidingTabBasicFragment.java:

private void createAdapters(View view){
    Log.v(TAG, "createAdapters()");
    try {
        //TODO createAdapters() work out why the app's ghosting
        ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
        int currentItem = mViewPager.getCurrentItem();

        SamplePagerAdapter testAdaptor = (SamplePagerAdapter)mViewPager.getAdapter();
        if ( testAdaptor == null ) {
            Log.v(TAG, "createAdapters() - new SamplePagerAdapter() to be added");
            mViewPager.setAdapter(new SamplePagerAdapter());
        }

        mViewPager.setCurrentItem(currentItem);

        SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
        mSlidingTabLayout.setViewPager(mViewPager);

        rebuildViews = false;
    } catch (NullPointerException e) {
        Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
    }
}

From the main Activity:

@Override
public void onNavigationDrawerItemSelected(int position, int lastPosition) {
    Log.v(TAG, "onNavigationDrawerItemSelected - entered");
    Intent intent;
    String createdFileName;

    // update the main content by replacing fragments

    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    onSectionAttached(position + 1);

    switch (position) {
        case 0: // Main - Vitals
            Log.v(TAG, "adding a 'vitalFrag' to the fragment stack");
            transaction.replace(R.id.main_content_fragment, new SlidingTabsBasicFragment(), "vitalFrag").addToBackStack(null).commit();
            break;
        case 1: // Settings
...


@Override
public void onBackPressed(){
    Log.v(TAG, "onBackPressed - entered");
    // Catch back action and pops from backStack
    // (if you called previously to addToBackStack() in your transaction)
    if (getFragmentManager().getBackStackEntryCount() > 0){
        // If Open, close the Navigation Drawer, as can be confusing if the Navigation
        // Drawer shows a different Option / Fragment as selected, after the previous
        // fragment has been restored
        NavigationDrawerFragment mNavFrag = (NavigationDrawerFragment)
                getFragmentManager().findFragmentById(R.id.navigation_drawer);
        if (mNavFrag != null && mNavFrag.isVisible() && mNavFrag.isDrawerOpen()) {
            mNavFrag.closeDrawer();
            mClosedDrawer = true;
        }
        // Pull back the last fragment
        getFragmentManager().popBackStack();
    }
    // Default action on back pressed
    else super.onBackPressed();
}


@Override
public void onVitalChanged() {
    Log.v(TAG, "onVitalChanged() entered");
    requestBackup();
    //TODO onVitalChanged() - finish - just invalidate the views
    SlidingTabsBasicFragment fragment = (SlidingTabsBasicFragment)  getFragmentManager().findFragmentByTag("vitalFrag");
    if (fragment != null) {
        //Log.v(TAG, "onVitalChanged() asking fragment to rebuild the Vital views");
        //fragment.setRebuildViews();
        Log.v(TAG, "onVitalChanged - replace the Results fragment");
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.main_content_fragment, new SlidingTabsBasicFragment(), "vitalFrag")
            .addToBackStack(null)
            .commitAllowingStateLoss();
    }
}

And from one of the fragments:

....

@Override
public void onResume() {
    Log.v(TAG, "onResume() - entered");
    if (rebuildViews) {
        invalidateViews(this.getView());    
    }
    ActionBar mActionBar = getActivity().getActionBar();
    if (mActionBar != null)
        mActionBar.setTitle(R.string.action_history);
    super.onResume();
}
arober11
  • 1,969
  • 18
  • 31
  • Doesn't sound like a GC issue to me. It sounds like a bug in your code. Been using the `SlidingTabLayout` for a while now in an app, and I¨ve never seen this issue before. Are you attaching a `SlidingTabLayout` to each `Fragment`? The back button shouldn't call `populateTabStrip`... – Darwind Feb 01 '15 at 21:31
  • Nope, only the Main fragment has a SlidingTabLayout in it, so the following code appears in the Activities onCreate, and inthe switch statement in the onNavigationDrawerItemSelected handler: `FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.replace(R.id.main_content_fragment, new SlidingTabsBasicFragment()).commit();'` – arober11 Feb 02 '15 at 15:51
  • But, aren't you using the `SlidingTabLayout` together with a `ViewPager`? – Darwind Feb 02 '15 at 15:57
  • Yes, my code varies very little from the sample: `private void createAdapters(View view){ Log.v(TAG, "createAdapters()"); try { ViewPager mViewPager = (ViewPager) view.findViewById(R.id.viewpager); int currentItem = mViewPager.getCurrentItem(); mViewPager.setAdapter(new SamplePagerAdapter()); mViewPager.setCurrentItem(currentItem); SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs); mSlidingTabLayout.setViewPager(mViewPager); rebuildViews = false; }` – arober11 Feb 02 '15 at 16:09
  • Could you show the code, that are used to change between the different fragments in the `ViewPager`? And please add it as an edit to the question instead of posting code in the comments field - it's really unreadable :-) – Darwind Feb 02 '15 at 16:11
  • WIll do, but have been able to work around the issue by: 1) adding / overriding onResume(), in each of the fragments to manually reset the actionBar title, and force a refresh of the applicable views in each Fragment. 2) Closing the Navigation Drawer if open, as reverting the fragment shown in the main pane is independent of flagging the Active menu item in the Drawer, and closing the drawer is easier than adding a callback interface to each onResume, to force any open Navigation Drawer to alter it's selection. – arober11 Feb 06 '15 at 20:53
  • Not sure I understand - did you fix the issue with the `SlidingTabLayout` titles being drawn on top of each other by doing what you described above? Also, you shouldn't let the `Fragments` control the `ActionBar` title. Whenever you change the `Fragments` let the `Activity` change the title of the `ActionBar`. It's redundant code writing it in every `Fragment` as well... – Darwind Feb 07 '15 at 02:17
  • Thanks for the ActionBar tip, i only added the onResume hack in each fragment as still haven't got to the bottom of why it was occasionally failing to entirely remove the previous tab strip. The set title logic was added as I also spotted an issue with the title not reverting if the NavigationDrawer is open. Will take your advise and shunt the code back to the owning Activity. – arober11 Feb 07 '15 at 02:29
  • But there shouldn't be more than one `TabStrip`? If you have several `TabStrips` then probably the issue is that the background is transparent, so they lay on top of each other. For the title thing, have a look at template app for adding a navigation drawer - it should be available when creating a new project from either Eclipse or Android Studio. – Darwind Feb 08 '15 at 15:28
  • Managed to get a few: **The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count:** when coming back to Slider from other functions. A quick search and this appears to be a known issue with the sample code, see [1](http://stackoverflow.com/questions/22943658/illegalstateexception-the-applications-pageradapter-changed-the-adapters-cont) - [2](http://stackoverflow.com/questions/17784476/viewpager-works-fine-at-first-time-but-on-reloading-again-getting-the-error-jav), so time to look at the borrowed code :( – arober11 Feb 12 '15 at 16:44
  • Those issues doesn't say anything about the `SlidingTabLayout`, but merely issues with the `ViewPager`? If you want you can send me your code with the `SlidingTabLayout` in and I can have a look at it if you like, to see if I can fix the issue :-) – Darwind Feb 13 '15 at 11:37
  • Cheers, I apologise for the state of the code but hadn't touched Java about 7 years, prior to deciding to have a go at hacking my first / this App. Also been hacked about a bit (frigged) to try to work out what's going on. Anyway some bits [here](https://drive.google.com/open?id=0Bz4jsEJm4xjIeWJMZS12d3VIQkU&authuser=0) – arober11 Feb 13 '15 at 15:41

0 Answers0