JDC JDC - 3 months ago 18
Android Question

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>

JDC JDC
Answer

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.

Comments