I have an app, that deals with fragments and ViewPager. I have three fragments in a ViewPager. When you switch between them, it always causes the other two fragments to call their's onCreateView methods. How to do it only once, only when FragmentActivity is created??? I've read some questions and tried the solutions, but the fragments still have the same behavior.
ListFragment onCreate called twice
onCreate() and onCreateView() invokes a lot more than required (Fragments)
Here is some code, if it helps you, guys:
MainActivity:
public class StartingActivity extends FragmentActivity implements View.OnClickListener { ViewPager viewPager; CirclePageIndicator pageIndicator; Button discount; Button qrCode; Button pay; TabHost tabHost; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.starting_layout); viewPager = (ViewPager) findViewById(R.id.pager); if (savedInstanceState == null) { Fragment firstPage = Fragment.instantiate(this, FindTovarFragment.class.getName()); Fragment secondPage = Fragment.instantiate(this, MainWindowActivity.class.getName()); Fragment thirdPage = Fragment.instantiate(this, MapActivity.class.getName()); if ((firstPage != null && !firstPage.isDetached())|| (secondPage != null && !secondPage.isDetached()) || (thirdPage != null && !thirdPage.isDetached())) { List<Fragment> viewPagerFragments = new ArrayList<Fragment>(); viewPagerFragments.add(firstPage); viewPagerFragments.add(secondPage); viewPagerFragments.add(thirdPage); PageAdapter pageAdapter = new PageAdapter(getSupportFragmentManager(), viewPagerFragments); viewPager.setAdapter(pageAdapter); pageIndicator = (CirclePageIndicator) findViewById(R.id.circle); pageIndicator.setViewPager(viewPager); pageIndicator.setCurrentItem(pageAdapter.getCount() - 2); } } }
MapActivity:
public class MapActivity extends Fragment implements OnMyLocationListener { //Тэг для логов private static final String TAG = "MapActivity"; List<Address> addressList; private static final String STRING_LOCATION = ""; ArrayList<TorgCentr> randomTorgCentr; ArrayList<String> torgCentrNames; Context context; AutoCompleteTextView searchTorgCentr; OverlayManager overlayManager; MapController mapController; TextView textView; double longitude; double latitude; double itemLongitude; double itemLatitude; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "MapActivity onCreateView"); View view = (LinearLayout) inflater.inflate(R.layout.map_layout, container, false); final MapView mapView = (MapView) view.findViewById(R.id.map); textView = (TextView) view.findViewById(R.id.searchlocation); searchTorgCentr = (AutoCompleteTextView) view.findViewById(R.id.autoCompleteTextView); mapView.showBuiltInScreenButtons(true); mapController = mapView.getMapController(); context = getActivity(); return view; } @Override public void onResume() { super.onResume(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "MapActivity onCreate"); } public void onActivityCreated(Bundle savedInstanceState) { Log.d(TAG, "MapActivity onActivityCreated"); context = getActivity(); SetRightMapDisplayAddress rightMapDisplayAddress = new SetRightMapDisplayAddress(); rightMapDisplayAddress.execute(STRING_LOCATION); DownloadSuperMarketsArray superMarketsArray = new DownloadSuperMarketsArray(); superMarketsArray.execute(); overlayManager = mapController.getOverlayManager(); overlayManager.getMyLocation().setEnabled(false); super.onActivityCreated(savedInstanceState); }
Second Fragment:
public class MainWindowActivity extends Fragment { private static final String TAG = "MainWindowActivity"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "MainWindowActivity onCreateView"); View view = (RelativeLayout) inflater.inflate(R.layout.main_window_layout, container, false); if (container == null) { return null; } return view; } }
And the third one:
public class FindTovarFragment extends Fragment { private static final String TAG= "FindTovarFragment"; Context context; ArrayList<Category> categories; Spinner categoryContainer; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log.d(TAG, "FindTovarFragment onCreateView"); View view = (LinearLayout) inflater.inflate(R.layout.find_tovar_main_layout, container, false); categoryContainer = (Spinner) view.findViewById(R.id.category); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); Log.d(TAG, "FindTovarFragment onActivityCreated"); DownloadCategory downloadCategory = new DownloadCategory(); downloadCategory.execute(); }
Logs for MapActivity:
06-20 11:06:37.709: DEBUG/MapActivity(1290): MapActivity onCreate 06-20 11:06:37.709: DEBUG/MapActivity(1290): MapActivity onCreateView 06-20 11:06:38.509: DEBUG/MapActivity(1290): MapActivity onActivityCreated
Then again and again:
06-20 11:07:53.239: DEBUG/MapActivity(1290): MapActivity onCreate 06-20 11:07:53.239: DEBUG/MapActivity(1290): MapActivity onCreateView 06-20 11:07:53.429: DEBUG/MapActivity(1290): MapActivity onActivityCreated 06-20 11:08:23.029: DEBUG/MapActivity(1290): MapActivity onCreate 06-20 11:08:23.039: DEBUG/MapActivity(1290): MapActivity onCreateView 06-20 11:08:23.269: DEBUG/MapActivity(1290): MapActivity onActivityCreated
Thank you very much in advance.
The onCreate() is called first, for doing any non-graphical initialisations. Next, you can assign and declare any View variables you want to use in onCreateView() .
onCreate is called on initial creation of the fragment. You do your non graphical initializations here. It finishes even before the layout is inflated and the fragment is visible. onCreateView is called to inflate the layout of the fragment i.e graphical initialization usually takes place here.
onActivityCreated() is a callback provided to Fragments ostensibly for when the activity is finished being created, but it ends up actually being tied into the Fragment view's lifecycle - it is actually called between onViewCreated() and onViewStateRestored() and can be called multiple times in cases where the Fragment ...
In a Fragment's Lifecycle, the onAttach() method is called before the onCreate() method.
ViewPager retain in memory 1 page by default, to either side of the current page. So it would not re-create those pages when swiping 1 page left/right of the current page. But when swipe more than 1 pages to left/right, it would re-create those page again, hence called OnCreateView(), OnCreate().
If app uses few pages 3, you can increase the number of pages to retain by calling,
mViewPager.setOffscreenPageLimit(2);
Described here
I would change your architecture for this one on the android developer documentation:
http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html
but I would change some things...
1-I would change this method:
/** * The Fragment's UI is just a simple text view showing its * instance number. */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_pager_list, container, false); View tv = v.findViewById(R.id.text); ((TextView)tv).setText("Fragment #" + mNum); return v; }
For something like this where we decide which fragment you populate depending the position of the viewPager:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); SupportFragmentManager ft = getChildFragmentManager().beginTransaction(); String tag = ""; Fragment fragment = null; switch (mNum) { case 0: fragment = new MyFragmentZero(); tag = FragmentTags.TAG_0; break; case 1: fragment = new MyFragmentOne(); tag = FragmentTags.TAG_3; break; case 2: fragment = new MyFragmentTwo(); tag = FragmentTags.TAG_2; break; default: break; } /*OPTIONAL We can pass arguments to the fragments Bundle args = new Bundle(); args.putInt(Arguments.ARG_POSITION, mNum); fragment.setArguments(args);*/ //Place the fragment in the container ft.replace(R.id.fragment_container fragment, tag); ft.commit(); //You need a base layout for all fragment and use nested fragments later or you can define the layout for each position(mNum) inside the switch. return inflater.inflate(R.layout.fragment_layout_default_for_all_views, container, false); }
Like this you will have a good architecture and once it is working like this should be fine.
Anyway you must know how the viewPager works populating the fragment in the different positions.
When you start on the position 0, then the fragment on the position 0 and the one of the position 1 are created.
Then when you swipe to the position 1 the fragment on the 2 position is created, so you have now the three fragments created on the different positions (0,1,2..assuming you have only 3 pages on the viewPager).
We swipe to the position 2, the last one, and the fragment on the first position (0) get destroy, so we have now the fragments on the positions 2 and 3.
I hope it helped and let me know if you have any problem. Cheers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With