I have an application that uses ActionBarSherlock and inside the main fragment I have a ViewPager which uses several fragments to display different objects of a list.
Main Fragment:
public class CollectionDemoFragment extends SherlockFragment {
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
ViewPager mViewPager;
public CollectionDemoFragment() {
setTitle(R.string.title);
setHasOptionsMenu(true);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.demo_fragment, container, false);
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
return view;
}
#Override
public void onPause() {
//This runs when the fragment goes to backstack
super.onPause();
}
#Override
public void onResume() {
//This runs when the fragment returns from backstack
super.onResume();
}
}
ViewPagerAdapter:
public class DemoCollectionPagerAdapter extends
FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return 100;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
Inside each of this fragments I can create a new Main fragment with a new list to display in the ViewPager and replace the content with this new fragment.
ViewPager Fragments:
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
//Setup components
return rootView;
}
#Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//Do something
}
super.setMenuVisibility(visible);
}
#Override
public void onPause() {
//This should run when the fragment goes to backstack
super.onPause();
}
#Override
public void onResume() {
//This should run when the fragment returns from backstack
super.onResume();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.someComponent:
Fragment newContent = new CollectionDemoFragment();
switchContent(newContent, true);
break;
}
}
public void switchContent(Fragment newContent, boolean addToBackStack) {
if (newContent != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
ft.replace(R.id.content_frame, newContent);
if (addToBackStack) {
ft.addToBackStack("" + newContent.getId());
}
ft.commit();
}
}
}
This works ok, until I press back and the previous main fragment returns from the backstack.
The screen is empty (since onCreateView is not called the layout is not inflated), the lifecycle methods from the fragments in the ViewPager are never called either when the main fragment enters the backstack, nor when it returns .
The only method called in the fragments of the ViewPager is the setMenuVisibility() so, only the code in there runs.
Anyone knows a way to fix this and why this happens?
Not sure if it matters but I have to support since android 2.3.
When you are creating the view adapter You have to pass the fragment child manager as argument - getChildFragmentManager() instead of getFragmentManager().
Instead of,
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getFragmentManager());
you should use,
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getChildFragmentManager());
Related
I am trying to replace the current active fragment inside ViewPager when item inside fragment's recycelerview is clicked. So far, I manage to pop up the Toast on the second fragment when the item on the first fragment is clicked, but the all the view of the second fragment is blank.
Here is my code:
MainActivity.class
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager = findViewById(R.id.view_pager);
FragmentAdapter adapter = new FragmentAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount() - 1);
}
// ..........
private static class FragmentAdapter extends FragmentStatePagerAdapter {
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return AllGenreFragment.newInstance();
case 1:
return DashboardFragment.newInstance();
case 2:
return NotificationFragment.newInstance();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
// ..........
}
AllGenreFragment.class
public class AllGenreFragment extends Fragment {
RecyclerView genreRV;
private AllGenreAdapter allGenreAdapter;
private List<Genre> genreList;
public static AllGenreFragment newInstance() {
return new AllGenreFragment();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_genre, container, false);
genreRV = v.findViewById(R.id.rv);
genreRV.setHasFixedSize(true);
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);
genreRV.setLayoutManager(layoutManager);
genreList = new ArrayList<>();
allGenreAdapter = new AllGenreAdapter(genreList, getContext());
genreRV.setAdapter(allGenreAdapter);
return v;
}
}
AllGenreAdapter.class
public class AllGenreAdapter extends RecyclerView.Adapter<AllGenreAdapter.ViewHolder> {
// .......
class ViewHolder extends android.support.v7.widget.RecyclerView.ViewHolder {
public ViewHolder(final View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Genre: " + genre_title.getText().toString(), Toast.LENGTH_SHORT).show();
AppCompatActivity activity = (AppCompatActivity) itemView.getContext();
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment allAnimeFragment = new AllAnimeFragment();
Bundle bundle = new Bundle();
bundle.putString("genreid", genre_id.getText().toString().trim());
allAnimeFragment.setArguments(bundle);
fragmentTransaction.replace(R.id.view_pager, allAnimeFragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
}
}
// .......
}
AllAnimeFragment.class
public class AllAnimeFragment extends Fragment {
RecyclerView animeRV;
private AllAnimeAdapter allAnimeAdapter;
private List<Anime> animeList;
String genreid;
public static AllAnimeFragment newInstance() {
return new AllAnimeFragment();
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_anime, container, false);
Bundle arguments = getArguments();
genreid = arguments.getString("genreid");
Toast.makeText(getContext(), genreid, Toast.LENGTH_SHORT).show();
// .....
return v;
}
}
Your approach is not really good, try below way:
Create a container fragment, called ContainerFragment, example, you will be using this fragment for your ViewPager.
The ContainerFragment should contain a container view, and add AllGenreFragment in the first them it is invoked.
In AllGenreFragment, create a callback, when an item in the RecyclerView be clicked, then in ContainerFragment will replace (or add) current fragment (AllGenreFragment) to AllAnimeFragment
First, create ContainerFragment,
public class ContainerFragment extends Fragment implements AllGenreFragment.OnAllGenreFragmentListener {
#Nullable #Override public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_container, container, false);
}
#Override public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initialLoad();
}
private void initialLoad() {
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, AllGenreFragment.newInstance())
.commit();
}
#Override public void onItemClicked() {
getChildFragmentManager()
.beginTransaction()
.replace(R.id.container, AllAnimeFragment.newInstance())
.commit();
}
}
This Fragment should implement a callback from AllGenreFragment for handling fragment transaction.
also, the xml layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Next step, add above fragment into ViewPager, we using ContainerFragment instead of AllGenreFragment.
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return ContainerFragment().newInstance();
case 1:
return DashboardFragment.newInstance();
case 2:
return NotificationFragment.newInstance();
}
return null;
}
Ok, so now come back to AllGenreFragment, we should create a CallBack that we implement in ContainerFragment
public interface AllGenreFragmentListener {
onItemClicked();
}
and then,
private AllGenreFragmentListener listener;
#Override public void onAttach(Context context) {
super.onAttach(context);
if (getParentFragment() instanceof AllGenreFragmentListener) {
listener = (AllGenreFragmentListener) getParentFragment();
}
}
so we have an instance of AllGenreFragmentListener, from now, whenever listener call onItemClicked, the method onItemClicked in ContainerFragment will be invoked.
Ok, let do it,
create below variable and method in your AllGenreAdapter:
private AllGenreFragmentListener listener;
public void setListener(AllGenreFragmentListener listener) {
this.listener = listener;
}
and update your ViewHodler
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Genre: " + genre_title.getText().toString(), Toast.LENGTH_SHORT).show();
if (listener != null)
listener.onItemClicked()
});
}
Don't forget call setListener method in your AllGenreFragment, so please add
#Override public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (allGenreAdapter != null) allGenreAdapter.setListener(listener);
}
That all,
I type this code by hand, not in my IDE so maybe it not compile, so please fix it if you face any compile error.
Note
If you want to keep the behavior of the BACK button, override onBackPressed in your MainActivity
#Override public void onBackPressed() {
Fragment f = getCurrentFragment();
if (f != null) {
if (f.getChildFragmentManager().getBackStackEntryCount() > 1) {
f.getChildFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
} else {
super.onBackPressed();
}
}
public Fragment getCurrentFragment() {
return (Fragment) viewPager.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
}
Also, add fragment into backStack whenever we add them to the container view (in your ContainerFragment)
private void initialLoad() {
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, AllGenreFragment.newInstance())
.addToBackStack(null)
.commit();
}
#Override public void onItemClicked() {
// change `replace` to `add` and add more `.addToBackStack(null)`
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, AllAnimeFragment.newInstance())
.addToBackStack(null)
.commit();
}
you should add a context in the constructor of your adapter
public class AllGenreAdapter(Context context) extends RecyclerView.Adapter<AllGenreAdapter.ViewHolder> {
// .......
}
then pass your activity to your adapter, use it to replace your fragment
My app have a fragmentActivity with tabBar which control over the view pager and contain 3 fragments ,when i update my class User in fragmentB,i need to display him in fragmentC.
my question is how to refresh fragmentC every time when i add new User.
before i wrote this question i tried all the solution from this questions:
1.Update ViewPager dynamically?
2.refresh fragment at reload
3.Update Fragment from ViewPager
4.ViewPager PagerAdapter not updating the View
5.How to update fragment content from activity (viewpager)?
here is my code
FragmentActivity:
public class MainActivityTab extends FragmentActivity {
public SectionsPagerAdapter mSectionsPagerAdapter;
public ViewPager mViewPager;
public static MainActivityTab instance = null;
public static MainActivityTab getInstance(){
return instance;
}
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_tab);
getWindow().setStatusBarColor(Color.rgb(191,76,12));
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.getTabAt(0).setIcon(R.drawable.icon_A);
tabLayout.getTabAt(1).setIcon(R.drawable.icon_B);
tabLayout.getTabAt(2).setIcon(R.drawable.icon_C);
mViewPager.setCurrentItem(1,false);
}
FragmentStatePagerAdapter:
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return FragmentA.newInstance();
case 1:
return FragmentA.newInstance();
case 2:
return FragmentC.newInstance();
default:
return null;
}
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return null;
}
}
FragmentB:
public class FragmentB extends Fragment {
EditText name;
EditText age;
Button btnSave;
public static FragmentB newInstance() {
FragmentB fragment = new FragmentB();
return fragment;
}
public FragmentB() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_new2, container, false);
name = (EditText) rootView.findViewById(R.id.name);
age = (EditText) rootView.findViewById(R.id.age);
btnSave = (Button) rootView.findViewById(R.id.btnSave);
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UserManager.getInstance().creteUser(name.getText().toString(),age.getText().toString());
}
});
return rootView;
}
}
FragmentC:
public class FragmentC extends Fragment {
TextView nameTxt;
TextView ageTxt;
public static FragmentC newInstance(){
FragmentC instance = new FragmentC();
return instance;
}
public FragmentC(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_new3, container, false);
nameTxt = (TextView) rootView.findViewById(R.id.nameTxt);
ageTxt = (TextView) rootView.findViewById(R.id.ageTxt);
showUser();
return rootView;
}
public void showUser(){
if(UserManager.getInstance().getUser().getName()!=null){
nameTxt.setText(UserManager.getInstance().getUser().getName().toString());
ageTxt.setText(UserManager.getInstance().getUser().getAge().toString());
}
}
}
You could create a callback like:
public interface UserChangedCallback{
void onUserChanged();
}
and implement this callback on every view/fragment where you want to access the user:
#Override
public void onUserChanged() {
adapter.notifyDataSetChanged();
// or if you don't have an adapter refresh your textfields or whatever you want
}
Register the callback on the usermanager via UserManager.getInstance().registerCallback(this). Internally the usermanager have to add the callback to an internal list.
Create a private function inside your usermanager:
private void notifyCallbacks() {
for(UserChangedCallback callback : registeredCallbacks) {
callback.onUserChanged();
}
}
If you add/modify/delete a user you always have to call this function at the end. For example:
public void addUser(User user) {
users.add(user);
notifiCallbacks();
}
Now every view will be notified and refreshed.
Important!
Don't forget to unregister the callback from the usermanager on onDestroy() to avoid memory leaks.
Found solution:
i used in the method onPageSelected,when position is 2 my fragment detach and afterwards attach the fragment.
working perfectly!
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(position==2){
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction().add(R.id.fragmant_new3, FragmentC.newInstance());
fragmentTransaction.detach(FragmentC.newInstance());
fragmentTransaction.attach(FragmentC.newInstance());
fragmentTransaction.commit();
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
I have FragmentActivity (MainFragmentActivity) that is calling some fragments. I will say the below one is the 3rd Fragment.
BaseFragment fragSensors = SensorsPagerFragment.newInstance(
m_objAppCredentials);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (bFirst)
ft.add(R.id.flControlContainer, fragSensors, strTag);
else
ft.replace(R.id.flControlContainer, fragSensors, strTag);
And below class holds a viewpaper which calls more fragment upon swipe.
And in that one of the fragment an activity is called.
When the back button is pressed from the activity. The 1st Fragment UI appears and its mixes with UI of one of the fragment in the viewpager.
How to destroy the UI of the fragment inside the viewpaper or to avoid UI mixing?
public class SensorsPagerFragment extends BaseFragment {
ViewPager m_oVP;
public SensorsPagerFragment() {
LogUtils.LOGD("DEBUG", "SensorsPagerFragment::CTOR");
}
public static SensorsPagerFragment newInstance(AppCredentials objAppCredentials) {
SensorsPagerFragment frag = new SensorsPagerFragment();
m_objAppCredentials = objAppCredentials;
return frag;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_sensors_pager, container, false);
m_oVP = (ViewPager) v.findViewById(R.id.vpSensors);
//pager.setOffscreenPageLimit(0);
// Attach the adaptor to the PAGER
m_oVP.setAdapter(buildAdapter());
return v;
}
private PagerAdapter buildAdapter() {
return (new SensorFragmentPA(getChildFragmentManager()));
}
#Override
public void onStop() {
super.onStop();
CustomToast.Warning(getActivity().getApplicationContext(),
"SensorsPagerFragment::onStop()", 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// class SensorFragmentPA
class SensorFragmentPA extends FragmentPagerAdapter {
public SensorFragmentPA(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return Constants.cTOTAL_PAGES;
}
#Override
public Fragment getItem(int nPageNum) {
SensorsFragment f = SensorsFragment.newInstance(m_objAppCredentials, nPageNum);
return f;
}
#Override
public String getPageTitle(int nPageNum) {
return Integer.toString(nPageNum + 1);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
}
}
I have resolved the issue.
I have implemented the callbacks in each fragment. And in the MainFragmentActivity replace the fragments.
Having a problem with FragmentStatePagerAdapter and screen change orientation (saving state I guess).
The layout of my app is the following:
Activity -->
Fragment A
Fragment B (contains a FragmentStatePagerAdapter) wich shows 2 fragments
-->
Fragment B1
Fragment B2
All the fragments mentioned inherit from a BaseFragment class that doesn't do anything special but keeping some "global" vars I need.
When Activity starts loads up Fragment A. From a menu I replace Fragment A with Fragment B. Fragment B source is the following:
public class Fragment B extends BaseFragment {
public static String TAG = "b_fragment";
private MyCustomPagerAdapter adapter;
private ArrayList<String> tags = new ArrayList<>();
private ViewPager mViewPager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new MyCustomPagerAdapter(getFragmentManager());
//adapter = new MyCustomPagerAdapter(getChildFragmentManager());
tags.add(FragmentB1.TAG);
tags.add(FragmentB2.TAG);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_sample, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
mViewPager.setAdapter(adapter);
SlidingTabLayout mSlidingTabLayout = (SlidingTabLayout)view.findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setViewPager(mViewPager);
}
class MyCustomPagerAdapter extends FragmentStatePagerAdapter {
//class MyCustomPagerAdapter extends FragmentPagerAdapter {
FragmentManager mgr;
public SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public PrepagatePagerAdapter(FragmentManager mgr) {
super(mgr);
this.mgr = mgr;
}
#Override
public int getCount() {
return 2;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentB1();
case 1:
return new FragmentB2();
}
return null;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
}
The problem happens when I go to Fragment B then go back again to Fragment A and change orientation: I see while debugging on the onAttach() method of Fragment A that in the FragmentManager Fragment B is no more present (replaced by Fragment A) but Fragment B1 and B2 are there and are called their rispective onAttach() methods, resulting in weird behaviours of the layout. Didn't the child fragments should be remove from the FragmentManager?
At the moment I don't know if more details are needed. I can give further if you need.
I have an application that uses ActionBarSherlock and inside the main fragment I have a ViewPager which uses several fragments to display different objects of a list.
Main Fragment:
public class CollectionDemoFragment extends SherlockFragment {
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
ViewPager mViewPager;
public CollectionDemoFragment() {
setTitle(R.string.title);
setHasOptionsMenu(true);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.demo_fragment, container, false);
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
return view;
}
#Override
public void onPause() {
//This runs when the fragment goes to backstack
super.onPause();
}
#Override
public void onResume() {
//This runs when the fragment returns from backstack
super.onResume();
}
}
ViewPagerAdapter:
public class DemoCollectionPagerAdapter extends
FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return 100;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
Inside each of this fragments I can create a new Main fragment with a new list to display in the ViewPager and replace the content with this new fragment.
ViewPager Fragments:
public static class DemoObjectFragment extends Fragment {
public static final String ARG_OBJECT = "object";
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_collection_object, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(
Integer.toString(args.getInt(ARG_OBJECT)));
//Setup components
return rootView;
}
#Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//Do something
}
super.setMenuVisibility(visible);
}
#Override
public void onPause() {
//This should run when the fragment goes to backstack
super.onPause();
}
#Override
public void onResume() {
//This should run when the fragment returns from backstack
super.onResume();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.someComponent:
Fragment newContent = new CollectionDemoFragment();
switchContent(newContent, true);
break;
}
}
public void switchContent(Fragment newContent, boolean addToBackStack) {
if (newContent != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
ft.replace(R.id.content_frame, newContent);
if (addToBackStack) {
ft.addToBackStack("" + newContent.getId());
}
ft.commit();
}
}
}
This works ok, until I press back and the previous main fragment returns from the backstack.
The screen is empty (since onCreateView is not called the layout is not inflated), the lifecycle methods from the fragments in the ViewPager are never called either when the main fragment enters the backstack, nor when it returns .
The only method called in the fragments of the ViewPager is the setMenuVisibility() so, only the code in there runs.
Anyone knows a way to fix this and why this happens?
Not sure if it matters but I have to support since android 2.3.
When you are creating the view adapter You have to pass the fragment child manager as argument - getChildFragmentManager() instead of getFragmentManager().
Instead of,
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getFragmentManager());
you should use,
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getChildFragmentManager());