Fragment is not recreated after popBackStack() - android

I have an Activity with a Layout named "container" where Fragments are inflated in using FragmentTransactions
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
transaction.replace(R.id.container, SomeFragment.newInstance());
transaction.addToBackStack(null);
transaction.commit();
One Fragment inflates another fragment with two more Fragments in a TabLayout. This is done with a TabLayout and a ViewPager. Everything works well until I pop it from the backstack.
getSupportFragmentManager().popBackStack();
When I do this, the tabs are recreated and all the lifecycle methods are called. However, they have no content. They layouts seem not to be inflated.
I have a method called initUI(View v) which is called in
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_tabs, container, false);
initUI(rootView);
return rootView;
}
It does the setup for the TabLayout.
private void initUI(View rootView) {
pager = (ViewPager) rootView.findViewById(R.id.viewPagerCollected);
tabLayout = (TabLayout) getActivity().findViewById(R.id.tabs);
pager.setAdapter(new MyPagerAdapter(getActivity().getSupportFragmentManager()));
tabLayout.setupWithViewPager(pager);
tabLayout.setVisibility(View.VISIBLE);
}
Again, this method is called but doesn't seem to do anything when popping the backstack.
What am I doing wrong here? Why is the Fragment not recreated properly even though the onCreateView and initUI are being called?
EDIT: In my TabsFragment, each Fragment has a RecyclerView. When clicking one of the Items, another Fragment opens up, displaying detailed information to the user.
Here the user can navigate back. When doing this, the TabsFragment is visible again but this time without any content. It seems like the inner fragments have not being inflated this time around.

First Add to back stack like this...
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
transaction.replace(R.id.container, SomeFragment.newInstance());
transaction.addToBackStack("YOUR_TAG");
transaction.commit();
After than try to popstackback()

Related

Shared element back animation without backstack

I use one activity multiple fragments in my app. I use a shared element animation. I have two fragments, one of them is a detail page.
I don't want to addToBackStack function for fragment transition. And the detail fragment returns without animation for some cases. (fragmentMain->fragmentDetail)
DetailFragment detailFragment = new DetailFragment();
Transition moveTransition = TransitionInflater.from(MainActivity.singleInstance)
.inflateTransition(android.R.transition.move); // android.R.transition.move
moveTransition.setDuration(400);
detailFragment.setSharedElementEnterTransition(moveTransition);
FragmentManager fragmentManager = MainActivity.getActivityFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
.addSharedElement(sharedView, sharedView.getTransitionName())
.replace(R.id.mainLayout, detailFragment);
fragmentTransaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
This code works for me. I know that if I use addToBackStack, fragmentDetail->fragmentMain reveal animation works automatically. But I don't want to the use back stack.
Below code doesn't works for fragmentDetail->fragmentMain.
detailFragment.setSharedElementReturnTransition(moveTransition);
mainFragment.setSharedElementEnterTransition(moveTransition);
FragmentManager fragmentManager = MainActivity.getActivityFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction()
.addSharedElement(textView, textView.getTransitionName())
.replace(R.id.mainLayout, mainFragment);
fragmentTransaction.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
How can I do shared element animation for this case?
Look at your onCreateView function. If It recreate the layout, it breaks the transition id.
Solution:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(inflatedView != null)
return inflatedView;
inflatedView = inflater.inflate(R.layout.fragment_blank, container,
return inflatedView;
}

Handling the backstack with fragments containing tabs

I'm trying to create an Android application which contains a single activity with a container and a navigation drawer. The initialy empty container loads fragments which has a ViewPager inside a tab layout in which I load a frgment with a FragmentTransaction:
public static void replaceFragmentInContainer(FragmentManager fragmentManager, Fragment fragmentToShow,
boolean addToBackStack)
{
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (addToBackStack)
{
transaction.addToBackStack(null);
}
transaction.replace(R.id.container, fragmentToShow);
transaction.commit();
}
I'm using v4 fragments with a v7 ActionBar in a v7 ActionBarActivity.
Every loaded fragment is a fragment which only loads tabs with other fragments which they hold the actual usability. An example of such tab loading fragment:
public class MainFragment extends TabsFragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View contentView = inflater.inflate(R.layout.fragment_main, container, false);
initTabsLayout(savedInstanceState, contentView, R.id.pager);
addTab("tabspectag1", "", R.drawable.draw1, Fragment1.class, null);
addTab("tabspectag2", "", R.drawable.draw2, Fragment2.class, null);
addTab("tabspectag3", "", R.drawable.draw3, Fragment3.class, null);
return contentView;
}
The problem I'm facing is with the backstack. When a fragment is added to the backstack and I press the back button, the app does go back to the previous fragment like I want to and I see the tabs layout itself, but the content of the tabs is empty like there was nothing loaded to that tab. When it happens, I manage to reload the tab's content only when choosing that screen again with the navigational drawer.
I've tried overriding the onBackPressed in the activity:
#Override
public void onBackPressed()
{
if (getFragmentManager().getBackStackEntryCount() > 0)
{
getFragmentManager().popBackStack();
} else
{
super.onBackPressed();
}
}
but that like I said, it's like I'm getting back to the previous fragment but the tab inside that fragment is not repainting the fragment it had.
What can be done to solve this issue?
Since I DO see the tabs layout of the original fragment in the backstack but not the fragment inside the tab, is it possible I just need to somehow refresh the tab content meaning repaint it? If I can do such a thing then how can I do it?
You didn't post the entire code but, bear in mind that when using fragments inside fragments, the outer fragment should use the childfragmentmanager instead of the regular fragment manager.
If you have an Activity, then you have a fragment that has a Viewpager and inside that viewpager the views are fragments, those outer fragments must use their own childfragmentmanager instead of the activities fragmentmanager.
Activity uses getFragmentManager() to instantiate and show new fragments. Fragments use getChildFragmentManager() to instantiate and show new inner fragments. (fragments inside fragments).
If you always use the same fragmentmanager to handle the transactions the behaviour will be unpredictable.
Your Viewpager should have an TabsAdapter associated that extends from FragmentStatePagerAdapter to show new fragments(and uses the getChildFragmentManager from the fragment instead of the activity).

Android. Navigation drawer. Backstack issues in Fragment

I am trying to implement app with navigation drawer.
I created application on Eclipse.
This is default(or template) navigation drawer application.
MainActivity has root FrameLayout which includes different fragments at different times.
By default, it contains fragment A.
When item B will be chosen from navigation drawer, it will replace fragment A to fragment B.
MainActivity:
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.container, fragmentB);
transaction.addToBackStack(null);
transaction.commit();
FragmentB is root fragment for fragmentB2, FragmentB3 etc.
I thought that in this way, it will be easier to save fragments state.
It is saving fragment state only for FragmentB2.
FragmentA(root A) onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
/* Inflate the layout for this fragment */
View view = inflater.inflate(R.layout.fragment_balance_root, container,
false);
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.replace(R.id.balance_root_frame, MainActivity.balanceMainFragment);
transaction.addToBackStack(null);
transaction.commit();
return view;
}
FragmentA2 OnCreateView():
View rootView = inflater.inflate(R.layout.fragment_balance_main,
container, false);
return rootView;
FragmentB(root B) onCreateView():
FragmentTransaction transaction = getChildFragmentManager()
.beginTransaction();
transaction.replace(R.id.tariffs_root_frame, MainActivity.tariffsMainFragment);
transaction.addToBackStack(null);
transaction.commit();
FragmentB2:
private static void goToTariffInfo() {
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.tariffs_root_frame, new TariffsInfoFragment());
transaction.addToBackStack(null);
transaction.commit();
}
Fragment B3:
View rootView = inflater.inflate(R.layout.fragment_tariffs_info,
container, false);
return rootView;
I have many questions, but they are related to each other.
1. How to avoid saving root fragment in backstack?
When I press back button on Fragment A2 it goes to A1 which is blank.
I have tried to remove addToBackStack from MainActivity. This caused to quit on only one press back button.
I have tried to remove addToBackStack from FragmentA. No effect.
2.How to set seperate backstack for different collections of fragments?
For example: Navigation drawer includes 2 items: ItemA and ItemB.
Each item can be considered as one section.
FragmenA->FragmentA2->FragmentA3
FragmentB->FragmentB2->FragmentB3
But in my situation, when I click on back button on Fragment B2, somehow app goes back to Fragment A2(which previously was opened)
Even on Fragment B3, back button causes to go to Fragment A2.
How to solve these problems?

Restore inner fragment

I'm making an app that in a certain FragmentActivity has a Tabhost hosting 2 Fragments.
One of them must have either a layout A showing up or a layout B showing up, while the other one has always the same layout.
FragmentActivity
Fragment1 (first tab)
LayoutA
LayoutB
Fragment2 (second tab)
LayoutC
In order to wrap the control of both layouts in separate modules, I made two Fragments, namely FragmentA and FragmentB, that use LayoutA and LayoutB respectively, making the activity look like this:
FragmentActivity
Fragment1 (first tab)
FragmentA
LayoutA
FragmentB
LayoutB
Fragment2 (second tab)
LayoutC
The problem I have is that I cannot make this stable against both:
the user leaving the app when first tab is shown
the user navigates to tab 2 and then back to tab 1
At first my code for Fragment1 looked like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = new FrameLayout(getActivity());
view.setId(1);
return view;
}
#Override
public void onStart() {
super.onStart();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(1, mCurrentFragment, "f1");
ft.commit();
}
#Override
public void onStop() {
super.onStop();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.remove(mCurrentFragment);
ft.commit();
}
Inside onStop I remove the fragment in order to attach it to the new FrameLayout created in OnCreateView when the Fragment restarts next time.
The problem with this code is that apparently I cannot do any transactions when user leaves the app, so it crashes with.
java.lang.RuntimeException: Unable to stop activity {my.package/my.package.MainTabHost}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
To solve the problem, I changed the removing of the fragment just before I try to add it to the FragmentTransaction in onStart:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = new FrameLayout(getActivity());
view.setId(1);
return view;
}
#Override
public void onStart() {
super.onStart();
FragmentTransaction ft = getFragmentManager().beginTransaction();
if(getFragmentManager().findFragmentByTag("f1") != null) {
ft.remove(mCurrentFragment);
}
ft.add(1, mCurrentFragment, "f1");
ft.commit();
}
This code has the other problem. Switching from the first tab to the second and then coming back to the first shows a blank layout for Fragment1.
Note: I set all fragments to retain their state.
Solved! I used the second code. I had to this sequence of steps inside onStart:
- detach the fragment
- add it to the new view
- attach it

ViewPager isn't loading the items after removed and re-added into FrameLayout

I'm trying to make a fragment to display tips for the user. The fragment's createView method returns a ViewPager and setup the PagerAdapter through AsyncTask. This fragment is added dinamically in the FragmentActivity when the user press a button. If the user reaches the last item of press the same button again, this fragment is removed from the FragmentActivity. It's important to note that I add the fragment to the FrameLayout idenfified by android.R.id.content.
Ok, the first time I press the button, it works as expected. But the second time I press the button, the ViewPager doesn't appear. When I use the View Hierarchy to see what's happenning, I see the ViewPager in the right place, but with no items. I debugged and noted that the getCount() of the PagerAdapter is called, but the getItem is never called.
This is the createView method of my fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View tipsView = inflater.inflate(R.layout.tip_manager_layout, container, false);
this.tipPagerAdapter = new TipPagerAdapter(getFragmentManager(), getArguments().getIntArray(TIP_LAYOUT_IDS_KEY));
this.viewPager = (ViewPager) tipsView.findViewById(R.id.tip_pager);
this.viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
if(position == (tipPagerAdapter.getCount()-1)){
stop();
}
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
// Workaround to set the PagerAdapter within a fragment transaction
new SetViewPagerAdapterTask().execute();
return tipsView;
}
I add the fragment this way:
FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(android.R.id.content, this, TAG);
fragmentTransaction.commit();
And remove the fragment this way:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.remove(tipManagerFragment);
fragmentTransaction.commit();
This is the layout inflated by the fragment:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tip_pager"
android:layout_width="fill_parent"
android:layout_height="175dp"
android:layout_gravity="center_horizontal|bottom"
android:paddingBottom="2dp" />
Could someone help me with this problem?
EDIT:
For a while, I'm using the show and hide methods of the fragment after adding it to the activity. But it's not the correct approach. I can't understand why I can't add again a fragment with a ViewPager. The ViewPager is added and removed correctly, but the second time, it simply doesn't show anything.
After a long time thinking about my problem, I had the following idea: maybe the problem is related to the fact that I'm removing the fragment that has the ViewPager, but I'm not removing the fragments used by the ViewPager. Then, these fragments continues in the FragmentManager and something strange happens when the new ViewPager tries to use them.
So, I started trying to remove all the fragments. To do this, I created a method in my FragmentPagerAdapter this way:
public void destroy(FragmentTransaction fragmentTransaction){
for(Fragment tipFragment : tipFragments){
fragmentTransaction.remove(tipFragment);
}
}
The adapter is using the tipFragments to create its content. So, I get a fragmentTransaction as parameter and I remove all these fragments. When I want to remove my fragment, I use this code:
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
tipPagerAdapter.destroy(fragmentTransaction);
fragmentTransaction.remove(TipManagerFragment.this);
fragmentTransaction.commit();
This way, I remove all the fragments and when I add the fragment which has the ViewPager again, everything works well.

Categories

Resources