javaandroidandroid-fragmentsandroid-tabbed-activity

FragmentPagerAdapter returns semi broke views on Reselect


I have a Tab Activity that has x amount of tabs. All the tabs load properly on the first load. If I go x+2 tabs away from a tab and then go back, some of the data and elements are missing.

I used the Android Studio's own Tabbed Activity generated template, as well as the Fragment templates for the tabs.

I have reviewed SO and a few others, but they do not seem to fit my model exactly. Or if they do, Im not seeing it.

Any help?

Here is my Master Tabbed Activity with some of the relevant imports.

import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;

public class MasterTabActivity extends AppCompatActivity {

    public static Intent newIntent(Context packageContext) {
        Intent intent = new Intent(packageContext, MasterTabActivity.class);
        Bundle bundle = new Bundle();
        intent.putExtras(bundle);
        return intent;
    }


    private SectionsPagerAdapter mSectionsPagerAdapter;

    private ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_master_tab);

        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
            //get some data
        }


        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        ActionBar ab = getSupportActionBar();
        if (ab != null) {
            ab.setDisplayHomeAsUpEnabled(true);
        }

        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.container);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        // Titles
        tabLayout.addTab(tabLayout.newTab().setText("Details"));
        tabLayout.addTab(tabLayout.newTab().setText("Photos"));
        tabLayout.addTab(tabLayout.newTab().setText("Notes"));

        //Add ICONS TO TEXT
        tabLayout.getTabAt(0).setIcon(R.drawable.ic_details);
        tabLayout.getTabAt(1).setIcon(R.drawable.ic_photos);
        tabLayout.getTabAt(2).setIcon(R.drawable.ic_notes);

        tabLayout.setTabTextColors(
                ContextCompat.getColor(this, R.color.colorPrimary), //unselected
                ContextCompat.getColor(this, R.color.colorDarkText) //selected
                                  );

        //Set the initial selected icons tab color
    tabLayout.getTabAt(0).getIcon().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.colorDarkText), PorterDuff.Mode.SRC_IN);
        tabLayout.getTabAt(1).getIcon().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN);
        tabLayout.getTabAt(2).getIcon().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN);



        // tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                mViewPager.setCurrentItem(tab.getPosition());
                tab.getIcon().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.colorDarkText), PorterDuff.Mode.SRC_IN);

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

                tab.getIcon().setColorFilter(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary), PorterDuff.Mode.SRC_IN);
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

                }
            });

refreshData();

        }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return DetailsFragment.newInstance(createdCallKey);
                case 1:
                    return PhotosFragment.newInstance(createdCallKey);
                case 2:
                    return NotesFragment.newInstance(createdCallKey);
                default:
                    return null;
            }
        }

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

And a sample of the fragments. At this point they are pretty much setup the same, save some basic GUI elements.

import android.support.v4.app.Fragment;

public class DetailsFragment extends Fragment {

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

    public static DetailsFragment newInstance(String callKey) {
        DetailsFragment fragment = new DetailsFragment();
        Bundle          args     = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

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

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

        View rootView = inflater.inflate(R.layout.fragment_details, container, false);
    //do all the view setup 
        return rootView;

    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }
}

Solution

  • In my Fragments I query the Tabbed Activity for some data. When a fragment moves more than x+2 tabs away, the Fragments onPausemethod (along with the other teardown methods) is called. Check the lifecycle documents for all the stages of the fragment.

    When you return to the tab, the onCreateView method (along with the other build methods baring 1onAttach1 and onCreate. In my example above, the fragment queries the Activity in onCreate.

    So I created a refreshData method:

     private void refreshData() {
                     someTextElement.setText(((MasterTabActivity) getActivity()).getCallDetailsDictionary().getString("CALdCallTaken").getString("SomeKey"));
        } 
    

    And moved the call to refreshData into onStart, first checking that the data in the activity is not null.

      @Override
        public void onStart() {
            super.onStart();
            Log.w(TAG, "-------------- onStart");
            if (((MasterTabActivity) getActivity()).getCallDetailsDictionary() != null) {
                refreshData();
            }
    
        }
    

    Now, whenever that view returns into view, it will call onStart and refresh its data.