I want to when button clicked to return to previous fragment. This is how I create fragment:
getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, statisticsSpecificStudentFragment)
.addToBackStack("StatisticsStudentOverallFragment")
.commit();
This is how I try and return to this fragment, from whom I started new fragment:
btDone.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().getSupportFragmentManager().popBackStack();
}
});
All that happends is that it reloads current fragment, like I added current one to stack but I did not.
Try
popBackStack("StatisticsStudentOverallFragment")
Or
addToBackStack(null)
and keep popBackStack() like you have it already.
Related
I am trying to open a fragment (PageFragment) from inside a fragment (UpcomingFragment).
When I open the fragment, the previous fragment UI is still present and I would not like this to be so.
I have tried both .getSupportFragmentManager(), and GetChildFragmentManager() neither of these solve the problem.And looking through simular thread on here, and I can't get a working result.
mRecyclerAdapter.setItemClickListener(new CardOnClicked() {
#Override
public void onCardClicked(int position) {
Log.d(TAG, "Test");
Fragment pageView = new PageFragment();
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction()
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.frag, pageView);
transaction.addToBackStack(null);
transaction.commit();
}
});
You can find my Github repository here:
https://github.com/KyleGwynDavies/aTV
You can see the problem here
https://imgur.com/a/BHkXOsc
Two fragments should never communicate directly. All communication needs to be done through the host activity. For that use an Interface.
Create an interface:
public interface IMainActivity {
void navigateFragment();
}
Add interface to the adapter override onAttachedToRecyclerView:
private IMainActivity mInterface;
#Override
public void onAttachedToRecyclerView(#NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
//instantiate interface when view attach to the recycler view
mInterface = (IMainActivity) mContext;
}
holder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mInterface.navigateFragment();
}
});
Finally, implement interface from to MainActivity and override the method then add your fragment.
#Override
public void navigateFragment() {
mViewProfileFragment = new ViewProfileFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.main_content_frame, mViewProfileFragment, getString(R.string.tag_fragment_view_profile));
transaction.commit();
}
I have a MainActivity in which I have Added a Fragment ==> BenefitsFragment
in BenefintsFragment there is a RelativeLayout
<RelativeLayout
android:visibility="gone"
android:background="#android:color/white"
android:id="#+id/benefitContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
I am adding another fragment like
browseBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
RelativeLayout mLayout = (RelativeLayout) view.findViewById(R.id.benefitContainer);
mLayout.setVisibility(View.VISIBLE);
getChildFragmentManager().beginTransaction()
.add(R.id.benefitContainer, new ConfirmPinFragment()).commitNow();
}
});
In my new ConfirmPinFragment I am trying to go back to old BenefitsFragment as
backBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
getChildFragmentManager().popBackStack();
}
});
However this popBackStack not working, if i try to remove using
getChildFragmentManager().beginTransaction().remove(ConfirmPinFragment.this).commitNow();
It crashes saying
java.lang.IllegalStateException: FragmentManager is already executing transactions
There are two things you need to do for this to work. But first of all there is really no need for commitNow(). The first thing you need to do is to add the fragment you want to go back to into the back stack during the transaction:
browseBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
RelativeLayout mLayout = (RelativeLayout) view.findViewById(R.id.benefitContainer);
mLayout.setVisibility(View.VISIBLE);
getChildFragmentManager().beginTransaction()
.add(R.id.benefitContainer, new ConfirmPinFragment())
.addToBackStack("benefits fragment").commit();
}
});
and when you go back use the getFragmentManager() instead of getChildFragmentManager() because you actually want the fragment manager that holds this fragment. Child fragment manager is the manager that manages the fragments inside this fragment.
backBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().popBackStack();
}
});
Hope this helps.
You add to the back state from the FragmentTransaction and remove from the backstack using FragmentManager pop methods:
FragmentManager manager = getActivity().getSupportFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove(myFrag);
trans.commit();
manager.popBackStack();
Be careful when using commitNow(), the fragment that you add won't be added into backstack. See this answer and this blog post for more info.
If you want to use backstack you should use commit() with addToBackStack() instead of commitNow()
The main reason why commitNow() is not adding into backstack is commitNow() will execute the transaction synchronously, if it'll added into backstack the transaction can broke the backstack order if there are another pending asynchronous transactions.
Using Kotlin and fragment-ktx using this one:
In your gradle:
implementation "androidx.fragment:fragment-ktx:$androidXFragmentKtxVersion"
In your Fragment
childFragmentManager
.findFragmentByTag(YOUR_TAG)?.let { fragment ->
childFragmentManager.commit(allowStateLoss = true) {
remove(fragment)
}
}
If you are not using childFragmentManager use requireActivity().supportFragmentManager instead
requireActivity().supportFragmentManage
.findFragmentByTag(YOUR_TAG)?.let { fragment ->
requireActivity().supportFragmentManage.commit(allowStateLoss = true) {
remove(fragment)
}
}
I'm attempting to implement a back stack while using fragments, but when using the Back button, I keep getting taken out of the app to the home screen.
Activity opens fragment A; Fragment A has a clickable TextView that opens fragment B (this works). Hitting BACK should return me to fragment A, but it takes me to the home screen instead.
Here is the activity's call to the opening of fragment A in onCreate:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_layout_container, new FragmentLogin(), "fragment_login")
.addToBackStack("login_screen")
.commit();
Log.d("Back", getFragmentManager().getBackStackEntryCount() +" <- Entry Count at LoginActivity.onCreate" );
At this point, the Log prints 0 <- Entry Count at LoginActivity.onCreate. Something I've done wrong keeps this from printing 1.
Then, the Fragment A has this listener:
forgottenPassword.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_layout_container, new FragmentForgottenPassword(), "fragment_password")
.addToBackStack("forgotten_password")
.commit();
Log.d("Back", getFragmentManager().getBackStackEntryCount() + " <- Entry Count at FragmentLogin.onCreateView.Listener");
}
});
The Log here prints 1 <- Entry Count at FragmentLogin.onCreateView.Listener. Here, the listener works and opens fragment B - but the back button returns me to the home screen.
Use this in your Activity it should pop out the fragments already added to backstack
#Override
public void onBackPressed()
{
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
Try Like This,
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
if (addToBackStack) {
transaction.addToBackStack(null);
} else {
getFragmentManager().popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
transaction.replace(R.id.fragment_layout_container, fragment);
transaction.commitAllowingStateLoss();
getFragmentManager().executePendingTransactions();
}
and Used it like this,
replaceFragment(new FragmentForgottenPassword(), true);
There is a GitHub library that will do this work for you!https://github.com/rathodchintan/Fragment-Back-StackWhenever you are displaying any new fragment, just push that fragment into stack using following code.
//here this fragment is our first fragment
homeListFragment = new HomeListFragment();
fragmentStack.push(homeListFragment);It has many other stack options too.
Solve by using getActivity()
I have this MainActivity.java and RepeatEntry.java
inside my MainActivity i have this code to have RepeatEntry ui
//i did hide two linear layout here with buttons and edittext inside it ,using the following method
hideTwoLinearLayout();
showCategoryContainerLayout();
Fragment fragment = new RepeatEntry();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//category_cont is a linear layout container for my fragment
ft.replace(R.id.category_cont, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
inside my RepeatEntry.java sample code
Button k = (Button) v.findViewById(R.id.button);
k.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Intent intent = new Intent(getActivity(),MainActivity.class);
// startActivity(intent);
// if i use popBackStack and also remove the code for intent , i cannot show what i hide
//note i have a method inside mainactivity to showTwoLinearLayout()
getFragmentManager().popBackStack();
}
});
Now my question is, do i have other option other than using intent to go back to MainActivity view
Note:Edited
You can add the transaction to backstack and then reverse with poping the backstack the code is here
Fragment fragment = new RepeatEntry();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
//category_cont is a linear layout container for my fragment
ft.replace(R.id.category_cont, fragment).addToBackStack("tag");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
And for going back to the activity view call this to pop backstack
FragmentManager fm = getFragmentManager();
fm.popBackStack();
Also you can use the tag to poping back the specific transaction with
fm.popBackStack("tag");
There is a method called onAttach in your fragment. You can write an interface and assign your fragment's activity like:
private MyFragmentListener mListener;
#Override public void onAttach(Activity activity) {
super.onAttach(activity);
mListener = ((MainActivity) activity);
}
public interface MyFragmentListener{
void onClicked(int value);
}
//Call your listener when button clicked or other events
... mListener.onClicked(position);
Or another solution is to use Otto or Eventbus to get rid unnecessary code
You can also go back in Fragment like
getActivity().getSupportFragmentManager().popBackStack();
any way i solve my problem just in case if anyone might see this.I came up with two solution which i think the first one is best for me.Thanks to Adnan Basar who give me idea.
First solution is so simple by just adding this code inside my onClick event
((MainActivity) getActivity()).showTwoLinearLayout();
((MainActivity) getActivity()).hideCategoryContainerLayout();
Second Solution I created Activity after extends Fragment{
Activity mainActivity;
And use override methods
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mainActivity= activity;
}
#Override
public void onDestroy() {
super.onDestroy();
// this is where i call the method for showing the twolinearlayout again
((MainActivity) mainActivity).showTwoLinearLayout();
((MainActivity) mainActivity).hideCategoryContainerLayout();
}
I have a HomeFragment that has a button, which when clicked calls the following:
Fragment frag = new CustFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.home_container, frag).commit();
Then in my FragmentActivity which is the fragments mentioned above, I have:
#Override
public void onBackPressed() {
getFragmentManager().popBackStack();
super.onBackPressed();
}
That's what I've tried, but if I'm on the frag fragment and I press the back button, it doesn't go back to the last fragment (the HomeFragment). Instead, it attempts to go back to the last Activity, but since there is none (i.e. the previous activity had finish() invoked on it), it just goes to the Android Home Screen.
What am I doing wrong?
PS: If I'm being unclear, just comment below and i'll try to clarify.
Change
#Override
public void onBackPressed()
{
getFragmentManager().popBackStack();
super.onBackPressed();
}
to
#Override
public void onBackPressed()
{
if(getSupportFragmentManager().getBackStackEntryCount() > 0)
getSupportFragmentManager().popBackStack();
else
super.onBackPressed();
}
and
fragmentManager.beginTransaction().replace(R.id.home_container, frag).commit();
to
fragmentManager.beginTransaction().replace(R.id.home_container, frag).addToBackStack(null).commit();
Add your fragment to back stack using addToBackStack(null) like..
fragmentManager.beginTransaction().replace(R.id.home_container, frag).addToBackStack(null).commit();
beginTransaction creates a new FragmentTransaction. It has a method addToBackstack. If you call it before you commit your transaction you can remove your overridden onBackPressed completely. Reference
You can use:
fragmentTransaction.addToBackStack(null);
and no need to take care of onBackPressed().
BTW in your onBackPressed() super.onBackPressed() means you are actually changing nothing.
It should have been something like:
if(currentFragmentIsCustFragment){
getSupportFragmentManager().popBackStack();
}else{
super.onBackPressed();
}