I am trying to implement onBackPressed on an activity with 3 Fragments. My issue is I implemented a "press again to exit" after some time method however when back button is clicked twice it returns to the previous fragment, not quitting. This happens when that fragment is called (i.e if I open the game and exit straight away it works like a charm). My onBackPressed method on MainActivity looks like this;
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount()!=0) {
getSupportFragmentManager().popBackStack();
}
this.findViewById(R.id.linearLayout1).setVisibility(View.VISIBLE);
if(mBackPressed + TIME_INTERVAL > System.currentTimeMillis() && getSupportFragmentManager().getBackStackEntryCount()==0){
super.onBackPressed();
System.exit(0);
this.finish();
}
else { Toast.makeText(getBaseContext(), "Press back once more to exit", Toast.LENGTH_SHORT).show(); }
mBackPressed = System.currentTimeMillis();
}
I basically want to check if the user is in the mainActivity layout so I could evade using popBackStack. Any solution would be appreciated, I could provide more information if this is not enough.
Thanks,
Bektaş
If you really want to quit, ignore the back stack altogether. Use this code.
#Override
public void onBackPressed() {
this.findViewById(R.id.linearLayout1).setVisibility(View.VISIBLE);
if(mBackPressed + TIME_INTERVAL > System.currentTimeMillis()){
this.finish();
return;
}
else {
Toast.makeText(getBaseContext(), "Press back once more to exit", Toast.LENGTH_SHORT).show();
}
mBackPressed = System.currentTimeMillis();
}
I think you might find this link useful
http://developer.android.com/training/implementing-navigation/temporal.html
it says that you can add the reference to the stack using this paturn
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
#Override
public void onBackPressed() {
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
getSupportFragmentManager().popBackStack(getSupportFragmentManager().getBackStackEntryCount(), getSupportFragmentManager().POP_BACK_STACK_INCLUSIVE);
android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(context);
builder.setCancelable(false);
builder.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
(Main Activity Name).super.onBackPressed();
}
}).create().show();
} else {
super.onBackPressed();
}
}
Related
I have taken one activity and with activity I have attached navigation drawer and the home fragment. In that navigation drawer there is a option of "Contact Us". When user click on that option a fragment gets open. But I am not able to maintain the stack of that. means when I am on contact us fragment then using navigation drawer again click on contact us it overlaps previous one. I have to press back button 2 times to go on home fragment. Please Help me how to maintain back stack for this. Here is my code..
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.rate:
Uri uri = Uri.parse("market://details?id=" + getPackageName());
Intent myAppLinkToMarket = new Intent(Intent.ACTION_VIEW, uri);
try {
startActivity(myAppLinkToMarket);
} catch (ActivityNotFoundException e) {
Toast.makeText(getApplicationContext(), "Unable to find source market app!", Toast.LENGTH_SHORT).show();
}
break;
case R.id.contact_us:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container_dashboard, ContactUsFragment.newInstance());
transaction.addToBackStack(null);
transaction.commit();
mDrawerLayout.closeDrawer(GravityCompat.START);
break;
}
return false;
}
});
After this code I use this to maintain back stack:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() != 0) {
getFragmentManager().popBackStack();
}
else new AlertDialog.Builder(this)
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Dashboard.super.onBackPressed();
}
})
.setNegativeButton("No", null)
.show();
}
But the issue is It's show exit dialogue on contact us fragment when ever I press back button. But I want firstly I reach to home fragment and after that If I press back button then it show exit dialogue.
I solved this by adding this in the onCreate method.
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() == 0){
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
menuToggle.setDrawerIndicatorEnabled(true);
// your dialog
}else{
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
menuToggle.setDrawerIndicatorEnabled(false);
// remove to your previous fragment
}
}
});
I want to completely it goes to the home of the phone when i back, but onBackPressed() is not working.
My Page is a fragment btw.
Use getActivity().onBackPressed(); in your fragment it will execute onBackPressed() of your parent activity
to be more accurate
Activity activity = getActivity();
if (activity != null) {
activity.onBackPressed();}
edit: use requireActivity() for avoiding nullpointer
requireActivity().onBackPressed();
onBackPressed callback is handled by your parent activity. So you can override callback on parent activity
XyzActivity.java:
#Override
public void onBackPressed() {
handleBackPress();
}
public void handleBackPress() {
Fragment visibleFragment = getSupportFragmentManager().findFragmentById(R.id.fragmentFrameLayout);
if (visibleFragment == null) {
return;
}else if (visibleFragment instanceof PreviewFragment) {
CommonFunctions.showDialogActionable(this, "Confirm", "Are you sure you want to exit?",
"Yes", (dialogInterface, i) -> {
finish();
}, "No", null, "", null, true);
return;
}else
finish();
super.onBackPressed();
}
For so far. I have created a simple quiz application on Android Studio. Everything works fine, including when I go from the FirstActivity.java to the Next Activity, which is named SecondActivity.java, and close the first activity with finish(),when the button is pressed, as shown in the following code:
public void onClick () {
button_next = (Button)findViewById(R.id.nextbtn);
button_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
finish();
}
});
The code works great But when I try to go from the Second Activity to the First Activity (Closing the Second Activity and going back to the first Activity), neither finish() nor onBackPressed() is working, it just closes the application completely, what code do I need to as soon as I press the button, close the SecondActivity.class and go to the FirstActivity.class?
If you want to go back to previous activity, dont put finish after you change your activity.
public void onClick() {
button_next = (Button) findViewById(R.id.nextbtn);
button_next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
}
});
}
If you have so many activities ,there is another way handle activity life cycle:
public class MyActivityManager {
private static MyActivityManager instance;
private Stack<Activity> activityStack;//activity's stack
private MyActivityManager() {
}
//singleton
public static MyActivityManager getInstance() {
if (instance == null) {
instance = new MyActivityManager();
}
return instance;
}
//push an activity to stack
public void pushOneActivity(Activity actvity) {
if (activityStack == null) {
activityStack = new Stack<Activity>();
}
activityStack.add(actvity);
}
//get last activity,fifo
public Activity getLastActivity() {
return activityStack.lastElement();
}
//remove an activity
public void popOneActivity(Activity activity) {
if (activityStack != null && activityStack.size() > 0) {
if (activity != null) {
activity.finish();
activityStack.remove(activity);
activity = null;
}
}
}
//finish all activity
public void finishAllActivity() {
if (activityStack != null) {
while (activityStack.size() > 0) {
Activity activity = getLastActivity();
if (activity == null) break;
popOneActivity(activity);
}
}
}
}
at the FirstActivity,you shall add
MyActivityManager.getInstance().pushOneActivity(FirstActivity.this);
at the SecondActivity, you want to go FirstActivity or other activity:
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
MyActivityManager.getInstance().finishAllActivity();
finish();
This question already has answers here:
Android Fragment handle back button press [duplicate]
(25 answers)
Closed 7 years ago.
I am new on android. I cant handle onBackPressed method. I have an Activity class which has four fragment like A,B,C, D. When i lunched Activity by default Fragment A is active and there are link on fragment A to move another Fragment. I want when move another Fragment like B,C,D from Fragment A and pressed Back button it return to Fragment A and if i pressed Back button from Fragment A it show a dialog box.
I used onBackPressed() like below
public void onBackPressed() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder
.setMessage("Do you really want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
MainActivity.this.finish();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
But it work on all fragment and i want to work only Fragment A
You have to handle such requirements in the Activity's onBackPressed only. I usually follow the following approach:
I keep an enum having all the fragments defined and a parameter to track the current fragment:
enum FRAGMENTS{
fragmentA, fragmentB, fragmentC, fragmentD
}
FRAGMENTS mCurrentFragment;
Now the logic where you change the fragment should have:
public void changeFragment(FRAGMENTS newFragment){
//Your logic
mCurrentFragment = newFragment;
}
And finally the logic onBackPressed:
onBackPressed{
if(mCurrentFragment == FRAGMENTS.fragmentA){
//Your code here of asking the user if he/she really wants to quit
super.onBackPressed();
}else{
changeFragment(getPreviousFragment(mCurrentFragment));
}
}
If you dont want to use enum, you can have final int or any other string values to represent different fragments and a mCurrentFragment parameter to keep a track of the currentFragment being shown and then you can easily play with the code in your Activity's onBackPressed method
Let me know if you need more clarification.
Add fragment to backStack while replacing
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack if needed
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
And then override onBackPressed method inside an Activity
So Here is your answer which you are looking for :)
Method 1
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// Your stuff here
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder.setMessage("Do you really want to exit?")
.setCancelable(false).setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
System.exit(0);
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
}
//Tell me if you face any issue
Method 2 or in your case just paste this method in your main activity so you can also achieve it what you want :)
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this);
// set title
alertDialogBuilder.setTitle("Exit");
// set dialog message
AlertDialog.Builder builder = alertDialogBuilder.setMessage("Do you really want to exit?").setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, close
// current activity
System.exit(0);
}
}).setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
If you want to override the onBack pressed method then add this code in your in onActivityCreated() method
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) {
getFragmentManager().popBackStack();
return true;
}
return false;
}
});
Use the below code hope it helps.
//Always replace/add your fragment with a tag so that you can use that tag in future
Fragment fr = getSupportFragmentManager().findFragmentByTag("Fragment_Name");//Fragment Name is a tag to identify fragment
if (fr == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, new Demo_Fragment(), "Fragment_Name").commit();
}
//Now override onBackPressed method in MainActivity Only no need to do it in Fragment Class
#Override
public void onBackPressed() {
Fragment fr = getSupportFragmentManager().findFragmentByTag("FragmentA");
if(fr==null)
//replace FragmentA
else
//Show Alert Box
}
For that you need to do following
Create method on the BaseFragment or Activity that save the current fragment object
public void setCurrentFragment(Fragment currentFragment) {
this.currentFragment = currentFragment;
}
and also create a method that return your current fragment object
public Fragment getCurrentFragment() {
return currentFragment;
}
now just you need to call the getCurrentFragment Method and checked that if the Fragment is an instance of the A fragment or not
if (getCurrentFragment() instanceof AFragment) {
showAlert
} else {
super.onBackPressed()
}
Let's say my first activity has the following code:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == SET_PLAN_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
fixedPlan = data.getParcelableExtra("fixedPlan");
recreate();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crop_rotation_planner);
// Hide the action bar; I don't want to see that hideous thing, yet.
getSupportActionBar().hide();
// Initialize imageLoader
MainActivity.imageLoader = new ImageLoader(getApplicationContext());
restore(savedInstanceState);
}
private void restore(Bundle savedInstanceState) {
// Check if activity has been launched previously
if (savedInstanceState != null) {
// Get saved crop rotation plan
fixedPlan = savedInstanceState.getParcelable("fixedPlan");
// Enable or disable btnViewPlan
checkIfEnoughCropFamilies();
// Set number of crop families
setNumberOfCropFamilies();
// get mSoilTypesList
mSoilTypesList = (ArrayList<String>) savedInstanceState.getStringArrayList("mSoilTypesList");
selectedTypeOfSoil = savedInstanceState.getString("selectedTypeOfSoil");
mPlantList = savedInstanceState.getParcelableArrayList("mPlantList");
// if mSoilTypesList hasn't been acquired, then execute loadSoilTypesFromNet to fetch data
if (mSoilTypesList == null) {
loadSoilTypesFromNet.execute();
}
// else if mSoilTypesList already exists, just display the soil types
else {
// only display if user hasn't selected soil yet
if (selectedTypeOfSoil == null) {
displaySoilTypes();
}
// if user has already selected soil type, then display plants
else {
getPlants();
}
}
}
else {
loadSoilTypesFromNet.execute();
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putStringArrayList("mSoilTypesList", mSoilTypesList);
savedInstanceState.putParcelableArrayList("mPlantList", mPlantList);
savedInstanceState.putString("selectedTypeOfSoil", selectedTypeOfSoil);
savedInstanceState.putParcelable("fixedPlan", fixedPlan);
}
#Override
protected void onDestroy() {
dismissAlertDialog();
dismissProgressDialog();
loadPlantsFromNet.cancel(true);
loadSoilTypesFromNet.cancel(true);
super.onDestroy();
}
#Override
public void onBackPressed() {
if (!fixedPlan.isEmpty()) {
AlertDialog.Builder builder = new AlertDialog.Builder(CropRotationPlannerActivity.this);
builder.setTitle(R.string.str_dbox_exit_crp_title);
builder.setMessage(R.string.str_dbox_exit_crp_message);
builder.setPositiveButton(R.string.str_dbox_exit_crp_ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
CropRotationPlannerActivity.super.onBackPressed();
}
});
builder.setNegativeButton(R.string.str_dbox_exit_crp_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert = builder.create();
alert.setCanceledOnTouchOutside(false);
alert.setCancelable(false);
alert.show();
}
else
super.onBackPressed();
}
And my proceeding activity has the following important code:
// We'll be sending our fixedPlan back to previous activity (CropRotationPlannerActivity)
#Override
public void onBackPressed() {
// TODO :: THINK OF THE SAVE FEATURE
final Intent intent = new Intent();
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.str_dbox_exit_title);
builder.setMessage(R.string.str_dbox_exit_message);
builder.setPositiveButton(R.string.str_dbox_exit_yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
intent.putExtra("fixedPlan", fixedPlan);
setResult(RESULT_OK, intent);
// TODO : Somewhat buggy code here?
// TODO : Takes quite sometime to process :/
finish();
PlanActivity.super.onBackPressed();
}
});
builder.setNegativeButton(R.string.str_dbox_exit_no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
setResult(RESULT_CANCELED, intent);
dialog.dismiss();
finish();
PlanActivity.super.onBackPressed();
}
});
builder.setNeutralButton(R.string.str_dbox_exit_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.setCancelable(false); // so as to prevent the back button from closing the dialog box
alert = builder.create();
alert.setCanceledOnTouchOutside(false); // prevents user from canceling dialog box by clicking outside
alert.show();
}
When the user exits the first activity and the Object fixedPlan doesn't have any contents, I want the user to exit to the main menu. When it doesn't have any contents, I want to pop a DialogBox so that the user is aware that the current activity contains important info and ask the user one more time if he really wants to exit.
To get to the next activity, fixedPlan should not be empty. And getting out from that activity, fixedPlan is never empty, too. But why does the back button not respond once the user goes back to the previous activity? What should I do?
NOTE THAT THIS ONLY HAPPENS WHEN positive button is pressed ( in the second activity). Another thing is that once I have pressed the positive button on the second activity, and the moment I'm in the first activity, and then I go back there and press the negative button, the back button works. It's really an issue with the positive button. BTW, I can feel the back button's vibration when pressed. LOL. Just that. It doesn't respond.
Adding finish() does not work either (to the else statement in my onBackPressed method for the first activity).
Try changing adding dialog.dismiss() before finish() in Positive button click event inside the second activity?
Also, I believe you should remove the calls to PlanActivity.super.onBackPressed();, both under positive and negative buttons click.