I am having issues with nested/child fragments. My use case is: I have Frag A as parent fragment and FragChild1, FragChild2, FragChild3 as child fragments to be displayed inside Frag A. Now on back press from FragChild3 it should work like :
FragChild3 -> FragChild2 -> FragChild1 -> FragA(ParentFrag).
The code I used to add child fragments are-
for ChildFrag1-
Fragment mChildFragment1 = new ChildFragment1();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.container_view, mChildFragment1);
transaction.addToBackStack("FragChild1");
transaction.commit();
for ChildFrag2-
Fragment mChildFragment2 = new ChildFragment2();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.container_view, mChildFragment2);
transaction.addToBackStack("FragChild2");
transaction.commit();
I have searched through StackOverflow for relevant answers but haven't yet found any proper answer/way of managing backstack for child fragments.
Your code seems good. Just override onbackpressed method in activity that contains parent fragment and put given code in it.
if (parentfragment.getChildFragmentManager().getBackStackEntryCount() > 1) {
parentfragment.getChildFragmentManager().popBackStackImmediate();
} else {
super.onBackPressed();
}
Now this behavior can be implemented with OnBackPressedDispatcher without overriding onBackPressed in an Activity.
In your parent fragment (where your fragment container is located) add this code in onAttach method:
override fun onAttach(context: Context) {
super.onAttach(context)
val backCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Remove all fragments from the childFragmentManager,
// but exclude the first added child fragment.
// This child fragment will be deleted with its parent.
if (childFragmentManager.backStackEntryCount > 1) {
childFragmentManager.popBackStack()
return
}
// Delete parent fragment
parentFragmentManager.popBackStack()
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, backCallback)
}
Than add fragments in your container like this:
childFragmentManager.commit {
replace(R.id.fragmentContainerRoot, fragment)
addToBackStack(null)
}
Pass the tag into the replace method. TAG can as simple as the fragments name (String). Change your code like this:
transaction.replace(R.id.container_view, mChildFragment1, "FragChild1");
transaction.addToBackStack("FragChild1");
transaction.commit();
Try This,
Fragment fragment= new ChildFragment1();
getChildFragmentManager().beginTransaction().replace(R.id.contentView, fragment).addToBackStack(fragment.getClass().getName()).commitAllowingStateLoss();
I am using drawer menu in my app.I select one option from menu and open fragment and from that fragment call an Activity.Since here it is working fine but when I press back button(OnbackPress) then app is crashed.
bellow is the error.
"Unable start activity...ClassCastException...cannot be cast to Home_Tab"
This is MainActivity code.
if (savedInstanceState == null) {
homefragment = Home_tab()
fragmentTransaction = fragmentManager!!.beginTransaction()
fragmentTransaction!!.replace(R.id.frame, homefragment)
fragmentTransaction!!.addToBackStack(null)
fragmentTransaction!!.commit()
} else {
homefragment = supportFragmentManager.fragments[0] as Home_tab //Crash at this line
}
Code from where backPress Called.
override fun onBackPressed() {
super.onBackPressed()
finish()
}
//Add a check like this before casting.
//It is a smart cast and you can directly use the result.
Fragment fragmentZero = supportFragmentManager.fragments[0]
if (fragmentZero is Home_tab) {
//Casting is done, you can directly use fragment here
homefragment = fragmentZero
}
Well based on your code you add the fragment to the fragmentmanager (regular one) but try to get it back from the supportfragmentmanager. Those are two different classes and your fragment can only extend one
You're are mixin fragment manager et support fragment manager, i'll go with suppport one since this is the right way to do it. To get current display fragment added with a container ID use findFragmentById
if (savedInstanceState == null) {
homefragment = Home_tab()
supportFragmentManager?.let{
fragmentTransaction = it.beginTransaction()
fragmentTransaction.replace(R.id.frame, homefragment)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
}
} else {
homefragment = supportFragmentManager.findFragmentById(R.id.frame) as Home_tab
}
How is it possible to go back to the last Activity one has been in from a Fragment? Let's assume we've Activity A and Fragment A. I launch Fragment A from Activity A, and now I want to go back to Fragment A. When I press on the back button on my phone it closes the app.
I launch the fragment by using the FragmentManager:
Fragment fragment = new Kontakt();
getFragmentManager().beginTransaction()
.add(R.id.kontaktfrag, fragment)
.commit();
Is the solution; popBackStackImmediate() or addToBackStack() ?
Firstly try addToBackStack when adding your fragment.
then you need to override your onBackPressed function of your activity, for example:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStackImmediate();
} else {
super.onBackPressed();
}
}
I tried myself and it worked.
try adding
getFragmentManager()
.beginTransaction()
.addToBackStack("")
.commit();
or just add .addToBackStack("") before .commit();
here is the code in your case,
Fragment fragment = new Kontakt();
getFragmentManager().beginTransaction()
.add(R.id.kontaktfrag, fragment)
.addToBackStack("")
.commit();
I'm working on android fragments and i am unable to keep the fragments in backstack i-e when i press back button it pushes me out of the Activity which starts fragments, i want to go back to previous fragment on backpress.
So far i have tried this but i am unable to keep the fragments in backstack.
getActivity().getFragmentManager().beginTransaction()
.replace(R.id.mainContainer, searchResultsFragment)
.addToBackStack(null)
.commit();
before you call commit() to commit transaction, you should add fragment to backstack addToBackStack(null) as you did in your provided code
then override onBackPressed() to pop fragment from stack
the issue you facing , you make your transaction with FragmentManager
getActivity().getFragmentManager().beginTransaction()
.replace(R.id.mainContainer, searchResultsFragment)
.addToBackStack(null)
.commit();
but you in onBackPressed() you using SupportFragmentManager
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0 ) {
getSupportFragmentManager().popBackStack();
}
}
to fix your issue , you must know what you match your fragment type (in your case searchResultsFragment) I mean if its extend Fragment or support Fragment
in case you extend fragment support
import android.support.v4.app.Fragment;
you should use getSupportFragmentManager() in both transaction and onBackPressed
in case you use fragment
import android.app.Fragment;
you should use getFragmentManager() in both transaction and onBackPressed
You have to overwrite onBackPressed in your activity. It is not enough only adding the fragment to back stack.
#Override
public void onBackPressed() {
FragmentManager fragmentManager = getSupportFragmentManager();
if(fragmentManager.getBackStackEntryCount() != 0) {
fragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
I just remove this line:
.addToBackStack(null)
And works for me.
I have an Activity and many fragments inflated in same FrameLayout
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
example: mainActivity > any fragment (press back button) > activity is blank.
In onCreate:
layout = (FrameLayout)findViewById(R.id.content_frame);
layout.setVisibility(View.GONE);
When I start a fragment:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, profileFragment);
ft.addToBackStack(null);
ft.commit();
layout.setVisibility(View.VISIBLE);
I suppose I need to make the frameLayout's visibility GONE again on back pressed, but how do I do this?
I tried onBackPressed and set layout.setVisibility(View.GONE); but I cannot go back through fragments, as I go directly to main page.
If you have more than one fragment been used in the activity or even if you have only one fragment then the first fragment should not have addToBackStack defined. Since this allows back navigation and prior to this fragment the empty activity layout will be displayed.
// fragmentTransaction.addToBackStack() // dont include this for your first fragment.
But for the other fragment you need to have this defined otherwise the back will not navigate to earlier screen (fragment) instead the application might shutdown.
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
else {
int fragments = getSupportFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
finish();
} else if (getFragmentManager().getBackStackEntryCount() > 1) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}
To add a fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.layout_main, dashboardFragment, getString(R.string.title_dashboard))
.addToBackStack(getString(R.string.title_dashboard))
.commit();
Sorry for the late response.
You don't have to add ft.addToBackStack(null); while adding first fragment.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, profileFragment);
// ft.addToBackStack(null); --remove this line.
ft.commit();
// ... rest of code
If you want to track by the fragments you should override the onBackPressed method, like this
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 1) {
finish();
} else {
super.onBackPressed();
}
}
You can override onBackPressed and check to see if there is anything on the backstack.
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
// make layout invisible since last fragment will be removed
}
super.onBackPressed();
}
Just don't add the first fragment to back stack
Here is the Kotlin code that worked for me.
val ft = supportFragmentManager.beginTransaction().replace(container, frag)
if (!supportFragmentManager.fragments.isEmpty()) ft.addToBackStack(null)
ft.commit()
On a recent personal project, I solved this by not calling addToBackStack if the stack is empty.
// don't add the first fragment to the backstack
// otherwise, pressing back on that fragment will result in a blank screen
if (fragmentManager.getFragments() != null) {
transaction.addToBackStack(tag);
}
Here's my full implementation:
String tag = String.valueOf(mCurrentSectionId);
FragmentManager fragmentManager = mActivity.getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentByTag(tag);
if (fragment != null) {
// if the fragment exists then no need to create it, just pop back to it so
// that repeatedly toggling between fragments doesn't create a giant stack
fragmentManager.popBackStackImmediate(tag, 0);
} else {
// at this point, popping back to that fragment didn't happen
// So create a new one and then show it
fragment = createFragmentForSection(mCurrentSectionId);
FragmentTransaction transaction = fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.main_content, fragment, tag);
// don't add the first fragment to the backstack
// otherwise, pressing back on that fragment will result in a blank screen
if (fragmentManager.getFragments() != null) {
transaction.addToBackStack(tag);
}
transaction.commit();
}
irscomp's solution works if you want to end activity when back button is pressed on first fragment. But if you want to track all fragments, and go back from one to another in back order, you add all fragments to stack with:
ft.addToBackStack(null);
and then, add this to the end of onCreate() to avoid blank screen in last back pressed; you can use getSupportFragmentManager() or getFragmentManager() depending on your API:
FragmentManager fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0) finish();
}
});
Final words: I don't suggest you to use this solution, because if you go from fragment1 to fragment 2 and vice versa 10 times, when you press back button 10 times it will do it in back order which users will not want it.
Almost same as Goodlife's answer, but in Xamarin.Android way:
Load fragment (I wrote helper method for that, but it's not necessary):
public void LoadFragment(Activity activity, Fragment fragment, string fragmentTitle = "")
{
var fragmentManager = activity.FragmentManager;
var fragmentTransaction = fragmentManager.BeginTransaction();
fragmentTransaction.Replace(Resource.Id.mainContainer, fragment);
fragmentTransaction.AddToBackStack(fragmentTitle);
fragmentTransaction.Commit();
}
Back button (in MainActivity):
public override void OnBackPressed()
{
if (isNavDrawerOpen()) drawerLayout.CloseDrawers();
else
{
var backStackEntryCount = FragmentManager.BackStackEntryCount;
if (backStackEntryCount == 1) Finish();
else if (backStackEntryCount > 1) FragmentManager.PopBackStack();
else base.OnBackPressed();
}
}
And isNavDrawerOpen method:
bool isNavDrawerOpen()
{
return drawerLayout != null && drawerLayout.IsDrawerOpen(Android.Support.V4.View.GravityCompat.Start);
}
I still could not fix the issue through getBackStackEntryCount() and I solved my issue by making the main page a fragment too, so in the end I have an activity with a FrameLayout only; and all other fragments including the main page I inflate into that layout. This solved my issue.
I had the same problem when dealing with Firebase's Ui Login screen. When back button was pressed it left a blank screen.
To solve the problem I just called finish() in my onStop() method for said Activity. Worked like a charm.
If you have scenario like me where a list fragment opens another details fragment, and on back press you first need to show the list fragment and then get out the whole activity then, addToBackStack for all the fragment transactions.
and then on the activity, do like this (courtesy: #JRomero's answer, #MSaudi's comment)
#Override
public void onBackPressed() {
int fragments = getFragmentManager().getBackStackEntryCount();
if (fragments == 1) {
// make layout invisible since last fragment will be removed
}
super.onBackPressed();
}
Just Comment or Remove transaction.addToBackStack(null) in your code.Below is code to change fragment in kotlin.
fun ChangeFragment(activity: MainActivity, fragment: Fragment) {
val transaction: FragmentTransaction =
activity.getSupportFragmentManager().beginTransaction()
transaction.replace(R.id.tabLayoutContainer, fragment)
transaction.commit()
}