I am working on creating a gallery like view with view pager and fragments using this implementation http://developer.android.com/training/implementing-navigation/lateral.html#horizontal-paging .
In my code I will fetch NUM_PAGES (integer) in viewpager from a web server for particular logged in user.
What I am doing:
My pages are populated with information when the user logs in to the app, which does many checks to populate one page, So I created all the views when onCreate() is called, and reusing them each time a fragment requires them.
when I launch my app with multiple pages in viewpager, navigating through page 1 through page 5, The app works fine, when I try to revisit the previous page, the app crashes with the "java.lang.IllegalStateException".
I am new to fragments and viewpager, Please help me solve this.
Thanks in advance.
Kiran
FATAL EXCEPTION: main
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:3435)
at android.view.ViewGroup.addView(ViewGroup.java:3306)
at android.view.ViewGroup.addView(ViewGroup.java:3251)
at android.view.ViewGroup.addView(ViewGroup.java:3227)
at android.support.v4.app.NoSaveStateFrameLayout.wrap(NoSaveStateFrameLayout.java:40)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:931)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
My Code :
protected void onCreate(Bundle savedInstance){
//my code here
//prepare views to be used with viewpager
setupViews();
//setup viewpager stuff
mAdapter = new ViewsAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
setContentView(R.layout.activity_main);
//other initializations here
}
public static class ViewsAdapter extends FragmentStatePagerAdapter{
public ViewsAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
// TODO Auto-generated constructor stub
}
#Override
public Fragment getItem(int position) {
// TODO Auto-generated method stub
Fragment fragment = new VehicleFragment();
Bundle args = new Bundle();
args.putInt(VehicleFragment.VEHICLE_INDEX, position);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return NUM_PAGES;// this value will be fetched at runtime from a server.
}
}
public class VehicleFragment extends Fragment {
public static final String VEHICLE_INDEX = "VEHICLE_INDEX";
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
int position = args.getInt(VEHICLE_INDEX);
Log.i("VehicleHome", "retrieving position : "+position+" in viewsList, where viewsList size = "+viewsList.size());
return viewsList.get(position);
}
}
private void setupViews() {
//prepare Views here, the views are created at runtime and added to viewsList (ArrayList)
//for reuse with fragments. So that each time a new instance of fragment is created we won't endup
//inflating layout file and initializing the view again and again..
//views logic
viewsList.add(view);
}
I guess you shouldn't create a new fragment every time a page is requested. Instead create them all at once and then just return the correct one:
public static class ViewsAdapter extends FragmentStatePagerAdapter{
private ArrayList<Fragment> fragments;
public ViewsAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
fragments = new ArrayList<Fragment>();
for (int i = 0; i < NUM_PAGES; i++) {
Fragment fragment = new VehicleFragment();
Bundle args = new Bundle();
args.putInt(VehicleFragment.VEHICLE_INDEX, position);
fragment.setArguments(args);
fragments.add(fragment);
}
}
#Override
public Fragment getItem(int position) {
// in case dynamic amount of fragments is needed, you can create
// new ones here if necessary (checking e.g. if position > fragments.size()-1)
fragments.get(position);
}
#Override
public int getCount() {
return NUM_PAGES;
}
}
Related
enter image description here
Before reading the question, please refer to image.
I am using viewpager to show the fragment.
Problem
In the fragment, I have used two edittext lets say editText1, editText2 now the problem is how I will get the editText data. I can only get the editText values when user click on next button but the next button is outside of fragment. How do I access the editText outside the fragment.
Before downvoting the question, let me know the reason so that I can improve my question.
Fragment java class
// newInstance constructor for creating fragment with arguments
public static BpDetails newInstance(int page) {
BpDetails fragmentFirst = new BpDetails();
Bundle args = new Bundle();
args.putInt("someInt", page);
fragmentFirst.setArguments(args);
return fragmentFirst;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
page = getArguments().getInt("someInt", 0);
}
// Inflate the view for the fragment based on layout XML
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.bp_details, container, false);
Log.i("View ",view.toString());
Log.i("DOB is ",Long.toString(Constants.dob));
systolic =(EditText) view.findViewById(R.id.systolic);
diastolic =(EditText) view.findViewById(R.id.diastolic);
return view;
}
ViewPager Activity
vpPager = (ViewPager) findViewById(R.id.view_pager);
adapterViewPager = new MyPagerAdapter(getSupportFragmentManager());
vpPager.setAdapter(adapterViewPager);
Fragment fragment=adapterViewPager.getItem(prevPage);
if (fragment.getClass().equals(BpDetails.class)){
Log.i("Call ","Yes");
}
findViewById(R.id.btn_prev).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// checking for last page
// if last page home screen will be launched
int current = getItem(-1);
if (current!=0)
prevPage=current-1;
if (current < 4) {
// move to next screen
vpPager.setCurrentItem(current);
} else {
//final reached.
}
}
});
findViewById(R.id.btn_next).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// checking for last page
// if last page home screen will be launched
int current = getItem(+1);
if (current!=0)
prevPage=current-1;
System.out.println("Prev page "+prevPage);
if (current < 4) {
// move to next screen
Fragment prevFragment=adapterViewPager.getItem(prevPage);
} else {
//final reached.
}
}
});
}
private int getItem(int i) {
return vpPager.getCurrentItem() + i;
}
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 4;
private static int mSelectedPosition;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
//mSelectedPosition=selectedPosition;
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return BasicDetails.newInstance(0);
case 1:
return BpDetails.newInstance(1);
case 2:
return BslDetails.newInstance(2);
case 3:
return Summary.newInstance(3);
default:
return null;
}
}
}
Create two getters inside your fragment like this.
public String getSystolic(){
return this.systolic.getText().toString();
}
public String getDiastolic(){
return this.diastolic.getText().toString();
}
BpDetails fr = (BpDetails)myAdapter.getItem(myViewPager.getCurrentItem());
String systolicString = fr.getSystolic();
I had a similar issue. .getItem() instantiates a new Fragment, so upon calling myAdapter.getItem(...) you would be getting null for all elements in the Fragment, but not null for the Fragment.
When I fixed this, what I had to do was create another method inside of MyPagerAdapter called getInstantiatedFragment:
public Fragment getInstantiatedFragment(int position)
{
return fragments.get(position);
}
fragments is a new field for the class:
private ArrayList<Fragment> fragments = new ArrayList<>();
I would override getItem() (as you have done already) and change it to:
#Override
public Fragment getItem(int position)
{
switch (position) {
case 0:
BasicDetails basicDetails = BasicDetails.newInstance(0);
fragments.add(basicDetails);
return basicDetails;
...
}
where you're adding the fragment to fragments before returning, then you would call:
BpDetails fr = (BpDetails)myAdapter.getInstantiatedItem(myViewPager.getCurrentItem());
to get the instance of the created fragment and then call
String systolicString = fr.getSystolic();
if you're using the previous answer's method.
This is so that you can keep track of the instantiated fragments in fragments. I'm sure there are better ways.
I am currently using Material Design in an Android app that I am making. In this app, I am using the Material Design tab layout to display some information that I am receiving. However when I tap the tabs, the animation is not smooth, and it is very abrupt. Sliding to go to the other tab, however is very smooth.
mTabLayout = (TabLayout) findViewById(R.id.chem_tab_layout);
mGenericAdapter = new GenericPagerAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.view_pager);
mPager.setAdapter(mGenericAdapter);
//Notice how the Tab Layout links with the Pager Adapter
mTabLayout.setTabsFromPagerAdapter(mGenericAdapter);
//Notice how The Tab Layout and View Pager object are linked
mTabLayout.setupWithViewPager(mPager);
mPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout){
#Override
public void onPageSelected(int position) {
mGenericAdapter.notifyDataSetChanged();
}
});
That is my code for setting the adapter, etc.
This is my custom adapter code for the tabs:
class GenericPagerAdapter extends FragmentStatePagerAdapter {
public GenericPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
ChemGridActivity.MyFragment myFragment = new ChemGridActivity.MyFragment();
return myFragment;
}
#Override
public int getCount() {
return 3; //returns number of tabs that need to be created
}
#Override
public CharSequence getPageTitle(int position) {
if (position == 0) return "Chemistry";
if (position == 1) return "Mathematics";
if (position == 2) return "Physics";
else return null;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
I feel that the choppy transition between tabs is caused by the overriden method onPageSelected method when I add onPageChangeListener. What do I add to this method to make tapping on tabs a smoother animation?
Without knowing much about the internals of your classes, I imagine the problem is not that you have a listener, but what you are doing inside that listener.
In the case of most adapters notifyDataSetChanged() will cause it to re-render the entire view again (including all pages).
Seeing as you haven't specified what the intent here with the notification is, it's hard to tell you how you can do this in an alternative way, but you do need to do something less intensive if you want the animation to remain smooth.
I suspect you just want to change which fragment is shown, in which case just use the FragmentManager where necessary, remembering to reuse fragments which have already been seen once.
EDIT Based on additional info in comments
#Override
public Fragment getItem(int position) {
//POSITION_SOMETHINHG would be one of a set of constants to indicate hwa to display
return ChemGridActivity.MyFragment.newInstance(ChemGridActivity.MyFragment.POSITION_SOMETHINHG);
}
public class ChemGridActivity.MyFragment ... {
private static final String KEY_DISPLAY_TYPE = "KEY_DISPLAY_TYPE";
public static final int POSITION_SOMETHINHG = 11111;
public static MyFragment newInstance(int display) {
MyFragment f = new MyFragment();
Bundle bund = new Bundle();
bund.putInt(KEY_DISPLAY_TYPE, display);
f.setArguments(bund);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mDisplay = args.getInt(KEY_DISPLAY_TYPE, 0);
}
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.my_layout, container, false);
//TODO: change something based on mDisplay
return view;
}
I have one details activity. Inside this, I'm using paging Controller with
<android.support.v4.view.ViewPager ..../> for fragment details view.
My code:
ViewPager pager = (ViewPager) findViewById(R.id.pagerHandbookDetails);
/** Getting fragment manager */
FragmentManager fm = getSupportFragmentManager();
/** Instantiating FragmentPagerAdapter */
DetailsFragmentAdapter pagerAdapter = new DetailsFragmentAdapter(fm,cases);
/** Setting the pagerAdapter to the pager object */
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(0);
Then, Details Fragment Adapter Class extends FragmentPagerAdapter
int PAGE_COUNT = 9;
#Override
public Fragment getItem(int arg0) {
DetailsFragment detailsFragment = new DetailsFragment();
Bundle data = new Bundle();
Log.d("Current Page", "Page " + arg0);
data.putInt("current_page", arg0);
detailsFragment.setArguments(data);
return detailsFragment;
}
Class Details Fragment extends Fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle data = getArguments();
int mCurrentPage = data.getInt("current_page", 0);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
layoutPaging = (LinearLayout) v.findViewById(R.id.layoutPagingView);
for(int i = 0; i < 9; i++){
ImageView image1 = new ImageView(layoutPaging.getContext());
image1.setTag(i);
if(i == mCurrentPage)
{
image1.setImageResource(R.drawable.black_dot);
}
else
{
image1.setImageResource(R.drawable.white_dot);
}
layoutPaging.addView(image1);
}
.......
}
It's working fine like this.
So whenever I swipe page, It'll obviously move all content of details fragment page. So it'll also move my custom view layout for paging. And it looks odd.
I want this layout static and change image content as per swipe pages.
If I'm taking this layout in main details class, then I'm not getting current page's value for changing an image from fragment adapter. It's only changing values inside fragment details class.
I'm stuck here.
you can add page indicators in your layout that is provided by:
https://github.com/Papercloud/SimpleViewPagerIndicator
you need to just place the control and set your viewpager controller's object to SimpleViewPagerIndicator.You can find sample code and implementation steps there
Using these classes, you can get indicators that will not scroll with pages
Just try this implement SimpleOnPageChangeListener for listen the page changes.
private static class PageListener extends SimpleOnPageChangeListener{
public void onPageSelected(int position) {
int currentPage = position;
}
}
And inside your ViewPagerActivity just write
private PageListener pageListener;
inside the onCreate() method do like this
pageListener=new PageListener()
pager.setOnPageChangeListener(pageListener);
Problem
A Fragment is not reattached to its hosting ViewPager after returning from another fragment.
Situation
One Activity hosting a Fragment whose layout holds a ViewPager (PageListFragment in the example below). The ViewPager is populated by a FragmentStateViewPagerAdapter. The single Fragments hosted inside the pager (PageFragment in the example below) can open sub page lists, containing a new set of pages.
Behaviour
All works fine as long as the back button is not pressed. As soon as the user closes one of the sub PageLists the previous List is recreated, but without the Page that was displayed previously. Swiping through the other pages on the parent PageList still works.
Code
A sample application can be found on github:
Activity
public class MainActivity extends FragmentActivity {
private static final String CURRENT_FRAGMENT = MainActivity.class.getCanonicalName() + ".CURRENT_FRAGMENT";
public static final String ARG_PARENTS = "Parents";
public void goInto(String mHostingLevel, String mPosition) {
Fragment hostingFragment = newHostingFragment(mHostingLevel, mPosition);
addFragment(hostingFragment);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addBaseFragment();
}
private void addBaseFragment() {
Fragment hostingFragment = newHostingFragment("", "");
addFragment(hostingFragment);
}
private Fragment newHostingFragment(String mHostingLevel, String oldPosition) {
Fragment hostingFragment = new PageListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARENTS, mHostingLevel + oldPosition +" > ");
hostingFragment.setArguments(args);
return hostingFragment;
}
private void addFragment(Fragment hostingFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentSpace, hostingFragment, CURRENT_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
}
PageListFragment
public class PageListFragment extends Fragment {
private String mParentString;
public PageListFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_hosting, container, false);
}
#Override
public void onResume() {
mParentString = getArguments().getString(MainActivity.ARG_PARENTS);
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewPager);
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
super.onResume();
}
private static class SimpleFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private String mHostingLevel;
public SimpleFragmentStatePagerAdapter(FragmentManager fm, String hostingLevel) {
super(fm);
this.mHostingLevel = hostingLevel;
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
PageFragment pageFragment = new PageFragment();
Bundle args = new Bundle();
args.putString(MainActivity.ARG_PARENTS, mHostingLevel);
args.putInt(PageFragment.ARG_POSITION, position);
pageFragment.setArguments(args);
return pageFragment;
}
#Override
public int getCount() {
return 5;
}
}
}
PageFragment
public class PageFragment extends Fragment {
public static final String ARG_POSITION = "Position";
private String mHostingLevel;
private int mPosition;
public PageFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.fragment_page, container, false);
setupTextView(contentView);
setupButton(contentView);
return contentView;
}
private void setupTextView(View contentView) {
mPosition = getArguments().getInt(ARG_POSITION);
mHostingLevel = getArguments().getString(MainActivity.ARG_PARENTS);
TextView text = (TextView) contentView.findViewById(R.id.textView);
text.setText("Parent Fragments " + mHostingLevel + " \n\nCurrent Fragment "+ mPosition);
}
private void setupButton(View contentView) {
Button button = (Button) contentView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
openNewLevel();
}
});
}
protected void openNewLevel() {
MainActivity activity = (MainActivity) getActivity();
activity.goInto(mHostingLevel, Integer.toString(mPosition));
}
}
After a lengthy investigation it turns out to be a problem with the fragment manager.
When using a construct like the one above the fragment transaction to reattach the fragment to the page list is silently discarded. It is basically the same problem that causes a
java.lang.IllegalStateException: Recursive entry to executePendingTransactions
when trying to alter the fragments inside the FragmentPager.
The same solution, as for problems with this error, is also applicable here. When constructing the FragmentStatePagerAdapter supply the correct child fragment manager.
Instead of
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
do
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));
See also: github
What Paul has failed to mention is, if you use getChildFragmentManager, then you will suffer the "blank screen on back pressed" issue.
The hierarchy in my case was:
MainActivity->MainFragment->TabLayout+ViewPager->AccountsFragment+SavingsFragment+InvestmentsFragment etc.
The problem I had was that I couldn't use childFragmentManagerfor the reason that a click on the item Account view (who resides inside one of the Fragments of the ViewPager) needed to replace MainFragment i.e. the entire screen.
Using MainFragments host Fragment i.e. passing getFragmentManager() enabled the replacing, BUT when popping the back-stack, I ended up with this screen:
This was apparent also by looking at the layout inspector where the ViewPager is empty.
Apparently looking at the restored Fragments you would notice that their View is restored but will not match the hierarchy of the popped state. In order to make the minimum impact and not force a re-creation of the Fragments I re-wrote FragmentStatePagerAdapter with the following changes:
I copied the entire code of FragmentStatePagerAdapter and changed
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
...
}
with
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach(f);
mCurTransaction.attach(f);
return f;
}
}
...
}
This way I am effectively making sure that that the restored Fragments are re-attached to the ViewPager.
Delete all page fragments, enabling them to be re-added later
The page fragments are not attached when you return to the viewpager screen as the FragmentStatePagerAdapter is not re-connecting them. As a work-around, delete all the fragments in the viewpager after popbackstack() is called, which will allow them to be re-added by your initial code.
[This example is written in Kotlin]
//Clear all fragments from the adapter before they are re-added.
for (i: Int in 0 until adapter.count) {
val item = childFragmentManager.findFragmentByTag("f$i")
if (item != null) {
adapter.destroyItem(container!!, i, item)
}
}
I'm new to Android developing and I would really appreciate some help here.
I'm using a fragment that contains a TextView and I'm using 5 instances of the same MyFragment class.
In the activity, i got a button and a ViewPager, and I need the button to update all the fragment instances content, whenever its clicked.
Here's the Activity
public class MainActivity extends FragmentActivity {
final static String[] CONTENT = {"a", "b"};
ViewPager pager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<MyFragment> fragments = new Vector<MyFragment>();
for(int i = 0; i < 5; i++){
MyFragment fragment = new MyFragment(CONTENT);
fragments.add(fragment);
}
PagerAdapter adapter = new PagerAdapter(this.getSupportFragmentManager(), fragments);
pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(adapter);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//method that isn't working
PagerAdapter adapter = (PagerAdapter)pager.getAdapter();
for(int i = 0; i < 5; i++){
MyFragment fragment = (MyFragment) adapter.getItem(i);
fragment.textView.setText(fragment.content[1]);
}
}
});
}
}
The Fragment
public class MyFragment extends Fragment{
String[] content;
TextView textView;
public MyFragment(String[] content) {
this.content = content;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_content, container, false);
textView = (TextView) view.findViewById(R.id.textView1);
textView.setText(content[0]);
return view;
}
}
And the FragmentPagerAdapter
public class PagerAdapter extends FragmentPagerAdapter{
List<MyFragment> fragments;
public PagerAdapter(FragmentManager fm, List<MyFragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int arg0) {
return fragments.get(arg0);
}
#Override
public int getCount() {
return fragments.size();
}
}
The OnClick method gives me a NullPointerException whenever i try to access a fragment from the adapter which is less than adapter.getCurrentItem() - 1, or more than adapter.getCurrentItem() + 1.
Any idea on how to update all the fragments at the same time?
Thanks in advance.
The easiest way to update those fragments is to use your code and set the number of fragments that the ViewPager holds in memory to the number of total fragments - 1(so all fragments are valid no matter at what page you are). In your case:
pager.setOffscreenPageLimit(4); // you have 5 elements
You can still use the method from my comment with the method onPageScrollStateChanged(so the update will start the moment the user starts swiping) to see when the user is starting to swipe the pager and update the fragments to the left and right of the currently visible fragment, but this will be a bit difficult to get right so I recommend to go with the first option.
Some points regarding your code containing fragments:
If you nest the fragment class make it static so you don't tie it to the activity object.
Don't create a constructor for a Fragment besides the default one. If the framework needs to recreate the fragment it will call the default constructor and if it is not available it will throw an exception. For example, try to change the orientation of the phone/emulator and see what happens(this is one of the cases when Android will recreate the fragments). Last, use a custom name for the ViewPager's adapter, you use PagerAdapter which is the name of the super class of FragmentViewPager and it's very confusing for someone reading your code.
If you need to pass data to the Fragment you could use a creation method like the one below:
public static MyFragment newInstance(String text) {
MyFragment f = new MyFragment();
Bundle b = new Bundle();
b.putString("content", text);
f.setArguments(b);
return f;
}
The text will be available in MyFragment by using getArguments().getString("content");