which function will be called after popBackStack is called?
I mean, when a certain fragment becomes active after calling popBackStack, which function will be called?
I did debug but onResume is called after certain activity is done something like clicking button etc.
But I need to call a function when fragment becomes active by getting called popBackStack
I just had the same question and tried to find out which default method is called when a fragment becomes active after calling popBackStack, but couldn't find any default methods called(here I mean onResume, onAttached, etc by default methods).
Hence I worked it out by calling the active fragment's method explicitly just after calling popBackStack.
For example, suppose we have two fragments A and B in the same activity and have clicked back button of the Android device on fragment A.
//fragment A
#Override
public void onResume() {
super.onResume();
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
// handle back button
FragmentManager fm = getFragmentManager();
fm.popBackStack();
//call fragment B.setBackButtonLister method
B fragment = (B)getFragmentManager().findFragmentByTag(B.TAG);
if (fragment != null){
fragment.setBackButtonListener();
}
return true;
}
return false;
}
});
}
This way, you can call any method of fragment B after you get the handle of B.
Hope this will help you, Cheers!
Related
I am trying to implement back navigation through my fragments which are called in specific order: A->B->C and by going back with hardware button I would like them to remain order.
I am using fragmenttransaction.replace in order to switch fragment with no addToBackStack because it made my ActionBarMenu to misbehave.
Problem is that when I am on fragment C back button is going back directly to A. I found out that it is because click event is executed twice I am going to B and directly to A.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setOnBackButtonPresed();
}
private void setOnBackButtonPresed() {
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener( new View.OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return false;
}
return false;
}
} );
}
private void goBackToDays() {
Log.e("fragmentC", "executing on back action")
}
logcat result:
03-15 08:37:17.353 21245-21245/com.test E/fragmentC: executing on back action
03-15 08:37:17.390 21245-21245/com.test E/fragmentC: executing on back action
Can anyone give me a hint how I can avoide twice button events?
I think "click event is executed twice" because you call both event ACTION_DOWN and ACTION_UP. Try this
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction()== KeyEvent.ACTION_DOWN)
{
goBackToDays();
return false;
}
return false;
}
2 things:
Even though you're replacing fragments, the old OnKeyListener stays there (and get's fired up later on). Try removing the old OnKeyListener on switching fragments.
Just as S-lightning pointed out, you need to bare in mind that there are two actions associated with a key event (KeyEvent.ACTION_DOWN and KeyEvent.ACTION_UP).
You can do two things
"it made my ActionBarMenu to misbehave." FIX this issue.
Override onBackPressed() on your Activity and find find out your current loaded fragment and replace with whichever you want.
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.your_view_container);
if (fragment instanceof FragmentThree) {
//replace with your fragment ie. FragmentTwo
} else if (fragment instanceof FragmentTwo) {
//replace with your fragment ie. FragmentOne
}
Return true if you want to "absorb" the key event and stop it from propagating up to the Activity, which has its own onBackPressed() implementation.
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return true; // <-- should be TRUE, not FALSE
}
return false;
Override the onBackPressed() method in hosting activity.
do like this.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
.
.
#Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
Here is the well explained answer. link
I have multiple fragments and I can switch between them, my problem is on how can I execute a method in a fragment before it goes to backstack.
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly. The code to switch from one fragment to another is:
public void switchFrgFromFrg(Fragment fragment, String tag, boolean isAddedToBackStack, int idContainer) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(idContainer, fragment, tag);
if (isAddedToBackStack) {
fragmentTransaction.addToBackStack(tag);
}
fragmentTransaction.commit();
}
Any help is apreciated.
Your fragment onResume() and onPause() will be called only when the Activity onResume() or onPause() that holds it is called. They are tightly coupled to the Activity, that's why your fragment is closing. I sugest you ti implement a back key listener as:
private void doBackActionListener(View view){
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//execute code
//then do standart go back action
getActivity().onBackPressed();
return true;
}
}
return false;
}
});
}
You will cal this in your onCreateView() and pass inflated view as parameter.
how can I execute a method in a fragment before it goes to backstack
When you fragment is visible you can execute as many methods as you want
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly.
That's because some Exception is arising in your code. It is better to show your console (Log messages) in your question.
if I launch a full-screen dialog like such
FragmentManager fragmentManager = getActivity().getFragmentManager();
DialogStyleCreator editor = new DialogStyleCreator();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.add(android.R.id.content, editor).commit();
How can I make it so that if I hit the android back arrow (in the top left of the menu) or the back button it closes the dialog instead of going back to the previous activity like in alert dialogs?
You may simply put your transaction in stack of fragment manager and override the function of back button
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (Integer.parseInt(android.os.Build.VERSION.SDK) > 5
&& keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) {
// Simply pop back your fragment stack here
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public void onBackPressed() {
// Simply pop back your fragment stack here
}
Since you have added the DialogFragment as transaction.add(android.R.id.content, editor).commit(); you may not have option to listen the dismiss call back.
I suggest you to create the DialogFragment instance and start it like
fm.beginTransaction().add(sampleDialog, "Dialog").commit();
and set the call back interface for Activity Back Button Click and call dismiss();
I want to go back to the last fragment in the back stack, so I want to make the back button popback the stack. Should I do this? and if so, should I override onBackPressed() or onKeyDown()?
#Override
public void onBackPressed()
{
Intent intent = new Intent(this,ABC.class);
startActivity(intent);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK ) {
// do something on back.
return true;
}
return super.onKeyDown(keyCode, event);
}
My fragments aren't being added to the back stack properly for some reason
I am using this to try to go back to the previous fragment, but the order is acting strange. What exactly should I do to make the order proper?
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft){
if(teamsFrag !=null)
{
if(manage.getBackStackEntryCount() > 0)
manage.popBackStack(manage.getBackStackEntryAt(manage.getBackStackEntryCount()-1).getName(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
//ft.detach(dataFrag);
}
Short answer? No.
Long answer? If you have to ask, No.
You should set your fragments up using the fragment manager so that the back button does what you want. You shouldn't override the back button instead of implementing your stack correctly.
I want to go back to the last fragment in the back stack, so I want to make the back button popback the stack.
This is the default behavior when you use FragmentTransaction#addToBackStack() while adding new Fragments with the FragmentManager.
I am having two fragments Frag A and Frag B which are rendered using view pager .
If user has swiped from A to B then presses back button(when in B) then user should go to A instead of coming out of view pager . How can we achieve this ?
Adding transaction to backstack does not seem to help .
Thanks
You have to override the onKeyDown() method in the Activity.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
This will capture the "back" button press event and send the user to the first item in the ViewPager.
There is also ViewPager#getCurrentItem() which can be used to go back only if the user swiped. An implementation like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && myViewPager.getCurrentItem() == 1) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
would send the user back to the previous page only if the user was on the next page. Else, it will register the "back" normally and the user will exit as expected.
You may want the case in which the user goes back to the previous page (assuming you have more than two pages). In which case, you want to implement the ViewPager.OnPageChangeListener() and save the position every time onPageSelected(int position) is called. If you implement them in a stack, then you can pop them off every time the user presses "back". Once the stack is empty, exit the app.
EDIT
As correctly stated in the comments by Jade Byfield, a slightly easier way to do this would be to use onBackPressed() in the Activity. This will only work in API levels 5+.
#Override
public void onBackPressed() {
if(i_dont_want_to_leave) {
myViewPager.setCurrentItem(0, true);
} else {
super.onBackPressed(); // This will pop the Activity from the stack.
}
}
On the Android Docs page
https://developer.android.com/training/animation/screen-slide.html#viewpager
I found an example of handling ViewPager sliding and there's a method
#Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0) {
super.onBackPressed();
}
else {
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
This selects a previous page or exits the current activity.
I think a better approach would be to delegate the back key handling to the respective fragments. I have used a CustomFragment which supports a method to handle the back key. All the Fragments will be extending from this CustomFragment.
public abstract class BackKeyHandlingFragment extends Fragment {
public abstract boolean handleBackKey();
}
Activity can delegate the backKey processing to current Fragment. Fragments can perform required actions in their respective implementation of handleBackKey method. The method can return true to tell activity not to process the back key. To go ahead with default back key action at Activity level, the method can return false.
public void onBackPressed() {
BackKeyHandlingFragment fragment = (BackKeyHandlingFragment) mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
// Fragment should return boolean according to app requirements after processing back key
if (!fragment.handleBackKey()) {
super.onBackPressed();
}
}