When a fragments visibility containing a ViewPager is set to GONE or INVISIBLE, the fragments in the ViewPager aren't initialized. They only seem to be initialized if the parent fragment is visible. How can I get around this problem? All I want to do is for the ViewPager to load its fragments (which is no more than two), even though the parent fragment isn't yet visible for the user.
Sample project to demonstrate the problem:
MainActivity:
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
final View startView = findViewById(R.id.startTab);
final View editView = findViewById(R.id.editTab);
getSupportFragmentManager().beginTransaction()
.replace(startView.getId(),
new StartFragment()).commit();
getSupportFragmentManager().beginTransaction()
.replace(editView.getId(),
new PagerFragment()).commit();
editView.setVisibility(View.GONE);
}
}
PagerFragment:
public class PagerFragment extends Fragment {
ViewPager pager;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Log.d("PageFragment", "onCreateView");
View result=inflater.inflate(R.layout.pager, container, false);
pager=(ViewPager)result.findViewById(R.id.pager);
pager.setAdapter(buildAdapter());
return(result);
}
private PagerAdapter buildAdapter() {
return(new SampleAdapter(getActivity(), getChildFragmentManager()));
}
}
SampleAdapter:
public class SampleAdapter extends FragmentPagerAdapter {
Context ctxt=null;
public SampleAdapter(Context ctxt, FragmentManager mgr) {
super(mgr);
this.ctxt=ctxt;
}
@Override
public int getCount() {
return(10);
}
@Override
public Fragment getItem(int position) {
Log.d("SampleAdapter","getItem");
return(EditorFragment.newInstance(position));
}
@Override
public String getPageTitle(int position) {
return(EditorFragment.getTitle(ctxt, position));
}
}
main_layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="400dp"
android:id="@+id/tabLayout">
<FrameLayout
android:id="@+id/startTab"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<FrameLayout
android:id="@+id/editTab"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</FrameLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tabLayout"
android:text="switch"
android:id="@+id/switchButton"/>
</RelativeLayout>
StartFragment:
public class StartFragment extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("StartFragment","onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View result=inflater.inflate(R.layout.start, container, false);
Log.d("StartFragment","onCreateView");
return(result);
}
}
EditorFragment:
public class EditorFragment extends Fragment {
private static final String KEY_POSITION="position";
static EditorFragment newInstance(int position) {
EditorFragment frag=new EditorFragment();
Bundle args=new Bundle();
args.putInt(KEY_POSITION, position);
frag.setArguments(args);
return(frag);
}
static String getTitle(Context ctxt, int position) {
return(String.format(ctxt.getString(R.string.hint), position + 1));
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("EditorFragment","onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View result=inflater.inflate(R.layout.editor, container, false);
EditText editor=(EditText)result.findViewById(R.id.editor);
int position=getArguments().getInt(KEY_POSITION, -1);
editor.setHint(getTitle(getActivity(), position));
Log.d("EditorFragment","onCreateView");
return(result);
}
@Override
public void onResume() {
super.onResume();
}
}
Came up with a solution for the problem. I added a OnAttachStateChangeListener to the viewpager, then calling setOffscreenPageLimit. This triggers populate() in ViewPager, which adds all the fragments to the adapter even if the visibility of PagerFragment is set to GONE. setOffscreenPageLimit can only be called after the view is attached to the window, otherwise populate() will return before the adapter gets populated with fragments.
PagerFragment:
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View result=inflater.inflate(R.layout.pager, container, false);
final ViewPager pager=(ViewPager)result.findViewById(R.id.pager);
pager.setAdapter(buildAdapter());
pager.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
pager.setOffscreenPageLimit(2);
}
@Override
public void onViewDetachedFromWindow(View v) {
}
});
return(result);
}