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.
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
Finally I was able to figure it out. Just need to override the destroyItem method so that it won't destroy objects. Hope this is going to be useful for someone.
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d(TAG, "destroy!");
}
Related
I have a button inside of a fragment that I need to be able to access in the activity to change it's text. I am using this code in my main activity:
CategoryFragment frag = new CategoryFragment();
getSupportFragmentManager().beginTransaction().add(R.id.activity_main, frag).commit();
frag.setButtonText(i);
The problem is the button is never initialized using the onCreateView() method (that method never even gets called) which causes a null pointer exception. I tried adding an onCreate() method in the fragment, which gets called, but I have to get the view in order to initialize my button. Since the view hasn't yet been initialized, I get another null pointer exception from the view. Here is my best attempt at the onCreate():
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
button = (Button) getView().findViewById(R.id.buttonFrag);
}
In OnCreateView() do like this :
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.yout_layout, container, false);
button = (Button) rootView.findViewById(R.id.buttonFrag);
return rootView;
}
You have completely misunderstood the way Fragment and Activity work with each other. An Activity mainly has the duty to "show" the Fragment, and you need to initialize the Button using your CategoryFragment class.
Override Category Fragment's onActivityCreated() and then add the following:
Button button = (Button) getView.findViewById(R.id.your_views_id);
button.setButton("Voila");
Study about Activity and Fragment Interaction. This might help u. http://simpledeveloper.com/how-to-communicate-between-fragments-and-activities/
You can use “static factory method” Refer following code
public class CategoryFragment extends Fragment {
/**
* Static factory method that takes an int parameter,
* initializes the fragment's arguments, and returns the
* new fragment to the client.
*/
public static CategoryFragment newInstance(String i) {
CategoryFragment f = new CategoryFragment();
Bundle args = new Bundle();
args.putInt("buttonText", i);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam = getArguments().getString("buttonText");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view=inflater.inflate(R.layout.fragment_category, container, false);
Button b=(Button) view.findViewById(R.id.button);
b.setText(mParam);
return view;
}
}
and from your activity just call
getSupportFragmentManager().beginTransaction().add(R.id.activity_main, CategoryFragment.newInstance(i)).commit();
In my application the fragment activity holds two fragments, Fragment A and Fragment B. Fragment B is a view pager that contains 3 fragments.
In my activity, to prevent that the fragment is recreated on config changes:
if(getSupportFragmentManager().findFragmentByTag(MAIN_TAB_FRAGMENT) == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.container, new MainTabFragment(), MAIN_TAB_FRAGMENT).commit();
}
Code for Fragment B:
public class MainTabFragment extends Fragment {
private PagerSlidingTabStrip mSlidingTabLayout;
private LfPagerAdapter adapter;
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.adapter = new LfPagerAdapter(getChildFragmentManager());
this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(adapter);
this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
this.mSlidingTabLayout.setViewPager(this.mViewPager);
}
}
Code for the adapter:
public class LfPagerAdapter extends FragmentPagerAdapter {
private static final int NUM_ITEMS = 3;
private FragmentManager fragmentManager;
public LfPagerAdapter(FragmentManager fm) {
super(fm);
this.fragmentManager = fm;
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public Fragment getItem(int position) {
Log.d("TEST","TEST");
switch (position) {
case 1:
return FragmentC.newInstance();
case 2:
return FragmentD.newInstance();
default:
return FragmentE.newInstance();
}
}
}
My problem is that I am not able to retain the state of the view pager an its child fragments on orientation changes.
Obviously this is called on every rotation:
this.adapter = new LfPagerAdapter(getChildFragmentManager());
which will cause the whole pager to be recreated, right? As a result
getItem(int position)
will be called on every rotation and the fragment will be created from scratch and losing his state:
return FragmentC.newInstance();
I tried solving this with:
if(this.adapter == null)
this.adapter = new LfPagerAdapter(getChildFragmentManager());
in onViewCreated but the result was that on rotation the fragments inside the pager where removed.
Any ideas how to correctly retain the state inside the pager?
You will need to do 2 things to resolve the issue:
1) You should use onCreate method instead of onViewCreated to instantiate LfPagerAdapter;
i.e.:
public class MainTabFragment extends Fragment {
private PagerSlidingTabStrip mSlidingTabLayout;
private LfPagerAdapter adapter;
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
this.adapter = new LfPagerAdapter(getChildFragmentManager());
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
this.mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(adapter);
this.mSlidingTabLayout = (PagerSlidingTabStrip) view.findViewById(R.id.sliding_tabs);
this.mSlidingTabLayout.setViewPager(this.mViewPager);
}
}
2) You will need to extend FragmentStatePagerAdapter instead of FragmentPagerAdapter
Android will automatically recreate your activity on configuration without this line android:configChanges="keyboardHidden|orientation|screenSize" in you manifest so that you can handle onConfiguration change yourself.
The only way then is to use onSaveInstanceState() in both your activityFragement to save viewPager state(current position for example) and in fragments where you need to save stuff
Example on how you can save current position of viewpager and restore it onConfiguration change
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
int position = mViewPager.getCurrentItem();
outState.Int("Key", position );
}
#Override //then restore in on onCreate();
public void onCreated(Bundle savedInstanceState) {
super.onCreated(savedInstanceState);
// do stuff
if (savedInstanceState != null) {
int position= savedInstanceState.getInt("Key");
mViewPager.setCurrentItem(position)
}
}
Of course, this is a very basic example.
Ps: to restore in fragment use onActivityCreated() instead of onCreate() method.
Here is another example on how to retain state : Click me!
I'm using loader in my ListView fragment, and it's getting recreated on pressing "back" button. Can you tell me how to handle this senario?
Here is my ListView fragment code. Here I have a boolean variable that I'm setting as true on clicking on list item. but once the back button is pressed onCreateView will get called so the backbutton will be false.
public class GTFragment extends SherlockFragment implements LoaderCallbacks<Cursor>{
ListView mTListview = null;
GoogleTasksAdapter mGTasksAdapter = null;
private SQLiteCursorLoader mTLoader=null;
private LoaderManager mTLoaderManager;
private String mSelectedListID = null;
private boolean mIsBackbuttonisPressed = false;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.task_home_activity, container, false);
if(!mIsBackbuttonisPressed)
getLoaderManager().initLoader(0, null, this);
mTListview = (ListView) view.findViewById(R.id.id_task_list_home_activity);
mGTasksAdapter = new GoogleTasksAdapter(getActivity());
mTListview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listview,
View clickedview, int position, long arg3) {
// TODO Auto-generated method stub
GoogleTaskItem item = new GoogleTaskItem();
Cursor coursor = ((GoogleTasksAdapter)listview.getAdapter()).getCursor();
if(coursor.moveToPosition(position))
{
mIsBackbuttonisPressed = true;
GoogleTaskController.get_googletask_controllerObj()
.LaunchTaskPreviewActivity();
}
}
});
mTListview.setAdapter(mGTasksAdapter);
mIsBackbuttonisPressed = false;
return view;
}
My fragment activity class code
public class TLActivity extends SherlockFragmentActivity {
LeftSliderTaskListOptions mTaskOptionsFragment = null;
GoogleTasksFragment mTFragment = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
setContentView(R.layout.layout_gt_list);
// FragmentTransaction tfragment = this.getSupportFragmentManager().beginTransaction();
mTFragment = new GTasksFragment();
t.replace(R.id.id_tfragment, mTFragment);
t.commit();
}
instead of
t.replace(R.id.id_tfragment, mTFragment);
use
t.add(R.id.id_tfragment, mTFragment);
It worked for me
I don't think that the accepted answer is right because Fragment.onSaveInstanceState will not be called until the activity hosting it needs to save its state: The docs states:
There are many situations where a fragment may be mostly torn down
(such as when placed on the back stack with no UI showing), but its
state will not be saved until its owning activity actually needs to
save its state.
In other words: if you're using a Activity with multiple fragments for each screen (which is very common), the fragment state will not be saved when you move the next screen.
You also can't use Fragment.setRetainInstance because he's meant only to fragments that aren't on the back stack.
Most of the time, you don't have to think about this but sometimes it's important. Like when you have scrolled a list and want to "remember" the scroll location.
I took a long time to realize that the fragments put on the back stack are kind of saved and you can reuse the view that you already created instead of creating one every time the fragment calls onCreateView. My setup is something like this:
public abstract class BaseFragment extends Fragment {
private boolean mSaveView = false;
private SoftReference<View> mViewReference;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mSaveView) {
if (mViewReference != null) {
final View savedView = mViewReference.get();
if (savedView != null) {
if (savedView.getParent() != null) {
((ViewGroup) savedView.getParent()).removeView(savedView);
return savedView;
}
}
}
}
final View view = inflater.inflate(getFragmentResource(), container, false);
mViewReference = new SoftReference<View>(view);
return view;
}
protected void setSaveView(boolean value) {
mSaveView = value;
}
}
public class MyFragment extends BaseFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setSaveView(true);
final View view = super.onCreateView(inflater, container, savedInstanceState);
ListView placesList = (ListView) view.findViewById(R.id.places_list);
if (placesList.getAdapter() == null) { // this check is important so you don't restart your adapter
placesList.setAdapter(createAdapter());
}
}
}
You have multiple options to rectify this issue.
Override onSaveInstanceState like this:
#Override
public void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("mIsBackbuttonisPressed", mIsBackbuttonisPressed);
}
and then in your onCreateView you can get your variable back by:
if (savedInstanceState != null)
mIsBackbuttonisPressed = savedInstanceState.getBoolean("mIsBackbuttonisPressed", false);
You can set this.setRetainInstance(true); in your onCreate method of your fragment.
If you could post your Activity code with creates your fragment I can also tell you other options. (P.S I cannot write it as a comment so posting it in the answer.)
I am trying to create a ViewPager which contains 5 fragments.
5 fragments "container", so each of them contain 2 fragments.
The 4 first fragments have the same layout and belong to the same class. The fifth is from an other class, and there is no problem with that one.
The problem is that when the activity launches, only 1 fragment seem to be working (the one at position 0 in viewPager). I tried to return new Fragment() at position 0 in my PagerAdapter, but when I do that it's the 2nd fragment that is working. (By working i mean displaying the list on the left, I still haven't taken care of the details fragment on the right)
Here is some code
CustomPagerAdapter.java
public class CustomPagerAdapter extends FragmentPagerAdapter{
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
public CustomPagerAdapter(FragmentManager fm, Context context) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
if(pos == 4)
return new OtherContainerFragment();
else
return new ContainerFragment(pos);
}
#Override
public int getCount() {
return 5;
}
ContainerFragment.java
public class ContainerFragment extends Fragment {
private int CONTAINER_TYPE;
public ContainerFragment(){
}
public ContainerFragment(int type){
CONTAINER_TYPE = type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_container, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
CustomListFragment frag = new CustomListFragment(CONTAINER_TYPE);
ft.replace(R.id.replaceable_list, frag);
ft.commit();
CustomListFragment.java
public class CustomListFragment extends SuperCustomListFragment{
private ArrayList<Model> mModels;
private int TYPE;
public CustomListFragment(){
}
public CustomListFragment(int type){
TYPE = type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mModels = new ArrayList<Model>();
if(TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL){
mAdapter = AppUtils.getJournalListAdapter(getActivity(), mModels);
new syncPapers().execute();
}else if(TYPE == AppConstants.FRAGMENT_TYPE_MOVIES){
mAdapter = AppUtils.getMoviesListAdapter(getActivity(), mModels);
new syncMovies().execute();
}
if(mAdapter != null)
mListView.setAdapter(mAdapter); //mListView is defined in the superClass
Here are the constants I use :
public class AppConstants {
public static final int FRAGMENT_TYPE_AGENDA = 0; //so Fragment at position 0 should be of type agenda
public static final int FRAGMENT_TYPE_NEWS = 1; // position 1 should be of type news
public static final int FRAGMENT_TYPE_MOVIES = 2; // ...
public static final int FRAGMENT_TYPE_JOURNAL = 3; // ...
}
And the xml for the container :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<LinearLayout
android:id="#+id/replaceable_list"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</LinearLayout>
<LinearLayout
android:id="#+id/replaceable_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/background" >
</LinearLayout>
</LinearLayout>
SO this code is not working, it seems that the list on the left in the fragment container is replaced in each fragment, and only the fragment at position 0 displays it. (Currently it displays the list with the adapter of type "JOURNAL", but it should display list of type "AGENDA".
--------------------
*BUT !...*
--------------------
If I create different fragment_container layout-files, and write IF conditions in the onCreateView and onViewCreated in the ContainerFragment.java, everything works fine.
So :
ContainerFragment.java
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL)
return inflater.inflate(R.layout.fragment_container_journal, container, false);
else if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_MOVIES)
return inflater.inflater(R.layout.fragment_container_movies, container, false);
else
return super.onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
CustomListFragment frag = new CustomListFragment(CONTAINER_TYPE);
if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_JOURNAL)
ft.replace(R.id.replaceable_journal_list, frag);
else if(CONTAINER_TYPE == AppConstants.FRAGMENT_TYPE_MOVIES)
ft.replace(R.id.replaceable_movies_list, frag);
else
return;
ft.commit();
I guess that's because in each fragment, I replace the LinearLayout of the same ID ? (replaceable_list)
I thought it was possible to share the same layout file for every fragments and didn't want to create 4 layout-files that would be the same. But it looks like I must do so ?
Or am I missing something here ?
Thank you for your time,
Though a very late response but I was facing same kind of issue and I fixed the issue by using
getChildFragmentManager().beginTransaction()
instead of
getActivity().getSupportFragmentManager().beginTransaction()
As in this case we are trying to make transaction from within a fragment (one out of the list of fragments which are attached to the ViewPager, thus the Activity holding the ViewPager) so we have to use getChildFragmentManager() here for desired results.
I was able to solve this by setting the id of the layout that is inflated within each fragment to its position.
What you would have to do is simply change the method onCreateView in you ContainerFragment class to:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_container, container, false);
v.setId(CONTAINER_TYPE)
return v;
This works because of the way the FragmentPagerAdapter implementation handles fragment tags.
public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
// add menu fragment
MainMenuFragment myFragment = new MainMenuFragment();
fragmentTransaction.add(R.id.menu_fragment, myFragment);
//add content
DetailPart1 content1= new DetailPart1 ();
fragmentTransaction.add(R.id.content_fragment, content1);
fragmentTransaction.commit();
}
public void onMainMenuSelected(String tag) {
//next menu is selected replace existing fragment
}
I have a need to display two list views side by side, menu on left and its content on right side. By default, the first menu is selected and its content is displayed on right side. The Fragment that displays content is as below:
public class DetailPart1 extends Fragment {
ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
ListAdapter adap;
ListView listview;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState!=null){
myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
listview.setAdapter(adap);
}else{
//get list and load in list view
getlistTask = new GetALLListTasks().execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.skyview_fragment, container,false);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("MYLIST_obj", myList );
}
}
The onActivityCreated and onCreateView are called twice. There are many examples out there using fragments. Since I am beginner in this subject, I am unable relate the example with my problem. I need a fool proof way to handle orientation change. I have NOT declared android:configChanges in manifest file. I need the activity destroy and recreate so that I can use different layout in landscape mode.
You are creating a new fragment every time you turn the screen in your activity onCreate(); But you are also maintaining the old ones with super.onCreate(savedInstanceState);. So maybe set tag and find the fragment if it exists, or pass null bundle to super.
This took me a while to learn and it can really be a pain when you are working with stuff like viewpager.
I'd recommend you to read about fragments an extra time as this exact topic is covered.
Here is an example of how to handle fragments on a regular orientation change:
Activity:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
TestFragment test = new TestFragment();
test.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
} else {
TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
}
}
}
Fragment:
public class TestFragment extends Fragment {
public static final String KEY_ITEM = "unique_key";
public static final String KEY_INDEX = "index_key";
private String mTime;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
if (savedInstanceState != null) {
// Restore last state
mTime = savedInstanceState.getString("time_key");
} else {
mTime = "" + Calendar.getInstance().getTimeInMillis();
}
TextView title = (TextView) view.findViewById(R.id.fragment_test);
title.setText(mTime);
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("time_key", mTime);
}
}
A good guideline about how to retain data between orientation changes and activity recreation can be found in android guidelines.
Summary:
make your fragment retainable:
setRetainInstance(true);
Create a new fragment only if necessary (or at least take data from it)
dataFragment = (DataFragment) fm.findFragmentByTag("data");
// create the fragment and data the first time
if (dataFragment == null) {