Search code examples
androidandroid-viewpagerandroid-tablayoutfragmentpageradapter

Android ViewPager with FragmentPageAdapter - only last fragment page is visible


I am using a ViewPager with a FragmentPagerAdapter. Each page is an instance of the same Fragment class, I am always using a fixed number of 7 pages (days of the week starting with today). Debugging shows that all Fragments are getting created and have the correct data at the time of creation. One interesting thing is although the adapter is creating the fragments in the order 0, 1, 2...6, the onCreateView of the fragments is called in the order 6, 0, 1, 2...5.

When run the app and open this activity, the first fragment page is blank, and then I can slide through the tabs and see that all of the pages are blank except the last one. But, the last page is not displaying the data from the last day, it is displaying one day eariler than it should, the next-to-last set of data.

I copied another ViewPager / FragmentPagerAdapter that I have that works, although that one has only 3 pages and uses a different Fragment for each page.

I am not seeing what I am doing wrong, I have been searching all day and have not found an answer yet. A lot of similar questions on here are resolved by using FragmentStatePagerAdapter instead of FragmentPagerAdapter. I already tried that and it behaves exactly the same as currently.

This is the activity hosting the ViewPager:

public class ForecastFaveRowClickedActivity extends AppCompatActivity {

    String distName = "";
    public List<ForecastEntry> forecastEntries = new ArrayList<>();
    ForecastPagerAdapter adapterViewPager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_forecast_detail);                

        // get the districts from the main activity
        Bundle bundle = getIntent().getExtras();            
        distName = bundle.getString("districtName");
        if (bundle.containsKey("forecastData")) {
            forecastEntries = bundle.getParcelableArrayList("forecastData");
        }                                

        Collections.sort(forecastEntries);


        // set up viewpager and display the first tab

        // ViewPager for tabs
        ViewPager viewPager = (ViewPager) findViewById(R.id.forecast_pager);
        adapterViewPager = new ForecastPagerAdapter(getSupportFragmentManager(), ForecastFaveRowClickedActivity.this);
        viewPager.setOffscreenPageLimit(7);

        // set the tab titles based on the forecast list for this district            
        String[] days = new String[7];
        int count = 0;
        for (ForecastEntry forecastEntry : forecastEntries) {
            days[count] = forecastEntry.forecastDay.substring(0,3);
            count++;
        }
        adapterViewPager.setTabTitles(days);

        viewPager.setAdapter(adapterViewPager);
        //viewPager.setCurrentItem(0);  // set to today's tab to start with            

        // give the tab layout to the viewpager
        TabLayout tabLayout = (TabLayout) findViewById(R.id.forecast_sliding_date_tabs);
        tabLayout.setupWithViewPager(viewPager);

    }

    // class for view pager adapter

    public class ForecastPagerAdapter extends FragmentPagerAdapter {
        private int NUM_ITEMS = 7;
        private String tabTitles[] = new String[7];
        private Context context;            

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

        public ForecastPagerAdapter(FragmentManager fragmentManager, Context context) {
            super(fragmentManager);
            this.context = context;
        }

        // returns total # of pages
        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        // returns the fragment to display for that page
        @Override
        public Fragment getItem(int position) {
            Fragment frag = new Fragment();
            ForecastEntry forecastEntry;
            Log.v("Fragment.getItem", Integer.toString(position));
            forecastEntry = ((ForecastFaveRowClickedActivity)context).forecastEntries.get(position);

            frag = FragmentForecastDay.newInstance(position, forecastEntry);                    
            return frag;                    
        }

        // returns the page title for the top indicator
        @Override
        public CharSequence getPageTitle(int position) {
            return tabTitles[position];
        }

        public void setTabTitles(String[] days) {
            tabTitles = Arrays.copyOf(days, days.length);
        }    
    }        
}

This is the layout for that activity:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
                                                 xmlns:tools="http://schemas.android.com/tools"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="match_parent"
                                                 android:fitsSystemWindows="true"
                                                 tools:context="com.districtoverview.ForecastFaveRowClickedActivity">


    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:titleTextColor="@color/colorWhite"
            android:elevation="4dp"
            android:theme="@style/AppTheme.AppBarOverlay"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    </android.support.design.widget.AppBarLayout>            

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="6dp"
        android:paddingTop="6dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        tools:context="com.districtoverview.ForecastFaveRowClickedActivity"
        tools:showIn="@layout/activity_forecast_detail"
        android:orientation="vertical">

        <android.support.design.widget.TabLayout
            android:id="@+id/forecast_sliding_date_tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingBottom="2dp"
            android:paddingTop="2dp"
            app:tabMode="scrollable"
            app:tabGravity="fill"
            style="@style/customForecastTabLayout" />

        <android.support.v4.view.ViewPager
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/forecast_pager"
            android:layout_width="match_parent"
            android:layout_height="0px"
            android:layout_weight="1"
            android:background="@android:color/white"
            tools:context="com.districtoverview.ForecastFaveRowClickedActivity">
        </android.support.v4.view.ViewPager>                
    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

This is the code for the Fragment class.

public class FragmentForecastDay extends Fragment {

    String label;
    int page;
    ForecastEntry forecastEntry;

    public static FragmentForecastDay newInstance(int page, ForecastEntry forecastEntry) {            
        FragmentForecastDay fragment = new FragmentForecastDay();
        Bundle args = new Bundle();
        args.putParcelable("forecastEntry", forecastEntry);
        args.putInt("page", page);
        fragment.setArguments(args);    
        return fragment;
    }


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

        View view = inflater.inflate(R.layout.fragment_forecast_day, container, false);                    

        page = getArguments().getInt("page", 0);
        forecastEntry = getArguments().getParcelable("forecastEntry");

        return view;            
    }


    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {

        super.onViewCreated(view, savedInstanceState);

        TextView headerDistNameTV = (TextView) getActivity().findViewById(R.id.dist_name_header_text);
        headerDistNameTV.setText(parentActivity.distName);

        TextView headerForecastDateTV = (TextView) getActivity().findViewById(R.id.forecast_date_header_text);            
        headerForecastDateTV.setText(forecastEntry.forecastDate);

        TextView headerTotalTechsTV = (TextView) getActivity().findViewById(R.id.total_techs_header_text);                        headerTotalTechsTV.setText(Double.toString(forecastEntry.totalTechs));

        TextView headerDayShiftTV = (TextView) getActivity().findViewById(R.id.day_shift_header_text);
        headerDayShiftTV.setText("Day Shift");

        TextView dayExpectedTechsTV = (TextView) getActivity().findViewById(R.id.day_shift_expected_text);            
        String dayExpectedTechs = "Expected " + Double.toString(forecastEntry.expectedTechs);
        dayExpectedTechsTV.setText(dayExpectedTechs);                

        TextView headerAfterHoursTV = (TextView) getActivity().findViewById(R.id.after_hours_header_text);
        headerAfterHoursTV.setText("After Hours");

        TextView afterHoursExpectedTechsTV = (TextView) getActivity().findViewById(R.id.day_shift_expected_text);    
        String afterHoursExpectedTechs = "Expected " + Double.toString(forecastEntry.afterHoursExpected);
        afterHoursExpectedTechsTV.setText(afterHoursExpectedTechs);                    
    }        
}

This is the fragment layout:

<?xml version="1.0" encoding="utf-8"?>

    <TableLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/forecast_day_table_layout"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.90"
        android:paddingTop="4dp"
        android:paddingBottom="4dp"
        android:paddingLeft="4dp"
        android:paddingRight="4dp"
        android:weightSum="1">
      <TableRow
            android:id="@+id/row_dist_name_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0.50">
            <TextView
                android:id="@+id/dist_name_header_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="#000"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
            android:id="@+id/row_date_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0.50">
            <TextView
                android:id="@+id/forecast_date_header_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="#000"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
          android:id="@+id/row_total_techs_header"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/total_techs_header_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
          android:id="@+id/row_total_techs"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/total_techs_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
          android:id="@+id/row_day_shift_header"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/day_shift_header_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
          android:id="@+id/row_day_shift_expected"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/day_shift_expected_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>          
      <TableRow
          android:id="@+id/row_after_hours_header"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/after_hours_header_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>
      <TableRow
          android:id="@+id/row_after_hours_expected"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:layout_weight="0.50">
          <TextView
              android:id="@+id/after_hours_expected_text"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textColor="#000"
              android:textAppearance="?android:attr/textAppearanceLarge"
              android:paddingBottom="5dp" />
      </TableRow>
  </TableLayout>

Solution

  • This was caused by my incorrect use of getActivity() rather than view. I had copied the code from another set of swipe tabs which was sitting on the main activity, but this set was inside of a fragment. I needed to refer to the view of the parent fragment.

    So for example this:

    (TextView) getActivity().findViewById(R.id.dist_name_header_text);
    

    Should have been this:

    (TextView) view.findViewById(R.id.dist_name_header_text);
    

    Once I made this change all child fragments used in the view pager were displayed correctly.