I wrote a piece of code that will give the user a prompt asking them to press back again if they would like to exit. I currently have my code working to an extent but I know it is written poorly and I assume there is a better way to do it. Any suggestions would be helpful!
Code:
public void onBackPressed(){
backpress = (backpress + 1);
Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();
if (backpress>1) {
this.finish();
}
}
I would implement a dialog asking the user if they wanted to exit and then call super.onBackPressed() if they did.
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes, new OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
WelcomeActivity.super.onBackPressed();
}
}).create().show();
}
In the above example, you'll need to replace WelcomeActivity with the name of your activity.
You don't need a counter for back presses.
Just store a reference to the toast that is shown:
private Toast backtoast;
Then,
public void onBackPressed() {
if(USER_IS_GOING_TO_EXIT) {
if(backtoast!=null&&backtoast.getView().getWindowToken()!=null) {
finish();
} else {
backtoast = Toast.makeText(this, "Press back to exit", Toast.LENGTH_SHORT);
backtoast.show();
}
} else {
//other stuff...
super.onBackPressed();
}
}
This will call finish() if you press back while the toast is still visible, and only if the back press would result in exiting the application.
I use this much simpler approach...
public class XYZ extends Activity {
private long backPressedTime = 0; // used by onBackPressed()
#Override
public void onBackPressed() { // to prevent irritating accidental logouts
long t = System.currentTimeMillis();
if (t - backPressedTime > 2000) { // 2 secs
backPressedTime = t;
Toast.makeText(this, "Press back again to logout",
Toast.LENGTH_SHORT).show();
} else { // this guy is serious
// clean up
super.onBackPressed(); // bye
}
}
}
Both your way and #Steve's way are acceptable ways to prevent accidental exits.
If choosing to continue with your implementation, you will need to make sure to have backpress initialized to 0, and probably implement a Timer of some sort to reset it back to 0 on keypress, after a cooldown period. (~5 seconds seems right)
You may also need to reset counter in onPause to prevent cases when user presses home or navigates away by some other means after first back press. Otherwise, I don't see an issue.
If you want to exit your application from direct Second Activity without going to First Activity then try this code..`
In Second Activity put this code..
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.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) {
setResult(RESULT_OK, new Intent().putExtra("EXIT", true));
finish();
}
}).create().show();
}
And Your First Activity Put this code.....
public class FirstActivity extends AppCompatActivity {
Button next;
private final static int EXIT_CODE = 100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
next = (Button) findViewById(R.id.next);
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivityForResult(new Intent(FirstActivity.this, SecondActivity.class), EXIT_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == EXIT_CODE) {
if (resultCode == RESULT_OK) {
if (data.getBooleanExtra("EXIT", true)) {
finish();
}
}
}
}
}
This is the best way, because if user not back more than two seconds then reset backpressed value.
declare one global variable.
private boolean backPressToExit = false;
Override onBackPressed Method.
#Override
public void onBackPressed() {
if (backPressToExit) {
super.onBackPressed();
return;
}
this.backPressToExit = true;
Snackbar.make(findViewById(R.id.yourview), getString(R.string.exit_msg), Snackbar.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
backPressToExit = false;
}
}, 2000);
}
additionally, you need to dissmis dialog before calling activity.super.onBackPressed(), otherwise you'll get "Activity has leaked.." error.
Example in my case with sweetalerdialog library:
#Override
public void onBackPressed() {
//super.onBackPressed();
SweetAlertDialog progressDialog = new SweetAlertDialog(this, SweetAlertDialog.WARNING_TYPE);
progressDialog.setCancelable(false);
progressDialog.setTitleText("Are you sure you want to exit?");
progressDialog.setCancelText("No");
progressDialog.setConfirmText("Yes");
progressDialog.setCanceledOnTouchOutside(true);
progressDialog.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
#Override
public void onClick(SweetAlertDialog sweetAlertDialog) {
sweetAlertDialog.dismiss();
MainActivity.super.onBackPressed();
}
});
progressDialog.show();
}
use to .onBackPressed() to back Activity specify
#Override
public void onBackPressed(){
backpress = (backpress + 1);
Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();
if (backpress>1) {
this.finish();
}
}
I just had this issue and solved it by adding the following method:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// click on 'up' button in the action bar, handle it here
return true;
default:
return super.onOptionsItemSelected(item);
}
}
You can also use onBackPressed by following ways using customized Toast:
enter image description here
customized_toast.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/txtMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableStart="#drawable/ic_white_exit_small"
android:drawableLeft="#drawable/ic_white_exit_small"
android:drawablePadding="8dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="center"
android:textColor="#android:color/white"
android:textSize="16sp"
android:text="Press BACK again to exit.."
android:background="#drawable/curve_edittext"/>
MainActivity.java
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
android.os.Process.killProcess(Process.myPid());
System.exit(1);
return;
}
this.doubleBackToExitPressedOnce = true;
Toast toast = new Toast(Dashboard.this);
View view = getLayoutInflater().inflate(R.layout.toast_view,null);
toast.setView(view);
toast.setDuration(Toast.LENGTH_SHORT);
int margin = getResources().getDimensionPixelSize(R.dimen.toast_vertical_margin);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL, 0, margin);
toast.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
Use this, it may help.
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Message")
.setMessage("Do you want to exit app?")
.setNegativeButton("NO", null)
.setPositiveButton("YES", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
UserLogin.super.onBackPressed();
}
}).create().show();
}
implementing onBackPressed() by System time, if pressed twice within 2 sec, then will exit
public class MainActivity extends AppCompatActivity {
private long backPressedTime; // for back button timing less than 2 sec
private Toast backToast; // to hold message of exit
#Override
public void onBackPressed() {
if (backPressedTime + 2000 > System.currentTimeMillis()) {
backToast.cancel(); // abruptly cancles the toast when pressed BACK Button *back2back*
super.onBackPressed();
} else {
backToast = Toast.makeText(getBaseContext(), "Press back again to exit",
Toast.LENGTH_SHORT);
backToast.show();
}
backPressedTime = System.currentTimeMillis();
}
}
Related
I wanted to make a snackbar dialog on double press to exit...(java)
Requested with these
On 1st time back pressed show dialogue " press back again to exit " for 2 seconds
On pressing back again show "do you want to exit ? " with the
confirmation button for 2 seconds
As like below -
Create id for your layout in activity_main
CoordinatorLayout coordinatorLayout;
#Override
public void onBackPressed() {
coordinatorLayout= (CoordinatorLayout) findViewById(R.id.coordinatorLayout);
if (!doubleBackToExitPressedOnce) {
this.doubleBackToExitPressedOnce = true;
Snackbar.make(coordinatorLayout, "Do you really want to exit?", Snackbar.LENGTH_LONG)
.setAction("YES", new View.OnClickListener() {
#Override
public void onClick(View view) {
//button action here
System.exit(0);
}
}).setActionTextColor(Color.YELLOW)
.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
}
Hope this helps
Here is the solution for you -
private final long DOUBLE_PRESS_BACK_TO_EXIT_TIME = 2000;
boolean doubleBackPressed = false;
#Override
public void onBackPressed() {
// todo: show the snackbar here.
this.doubleBackPressed = true;
utils.showToastLong(getString(R.string.press_again_to_exit));
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackPressed = false;
// todo: hide the snackbar here.
}
}, DOUBLE_PRESS_BACK_TO_EXIT_TIME);
}
To customize the Snackbar you may follow this link
Is there any way to disable in an activity the back button (to prevent show the previous activities), but also when you double press it, use it for exit??
I use this code that I found, but it only makes the second part. Close the app with double press..
What I try to do, is also prevent to go back and show the last visited activities. Thank you.
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Press again back for exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
UPDATE
I make the changes that you suggest, but now, it shows with the double back all the previous visited activities.
static final long THRESHOLD = 2000;
long backLastPressed;
boolean doubleBackToExitPressedOnce = false;
#Override
public void onBackPressed() {
if (System.currentTimeMillis() - backLastPressed < THRESHOLD) {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Press again back for exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
backLastPressed = 0;
return;
}
backLastPressed = System.currentTimeMillis();
// Otherwise, ignore this BACK press
}
You could store an internal variable that marks the time of when the BACK button was pressed. Every time in onBackPressed check if the time now is within your double-tap threshold and if so, register it as a double-tap.
Try something like this:
static final long THRESHOLD = 2000;
long backLastPressed = 0;
#Override
public void onBackPressed() {
if (System.currentTimeMillis() - backLastPressed < THRESHOLD) {
// TODO: Register double-tapped BACK button, put your "exit" code here
backLastPressed = 0;
return;
}
backLastPressed = System.currentTimeMillis();
// Otherwise, ignore this BACK press
}
Don't call super.onBackPressed() if you're trying to override the BACK button behavior.
I still don't have the reputation to comment.
To prevent visiting the previous activities, you could, in addition to the code to do something when you double-tap back button, clear the tasks when you enter in this activity.
This guide shows how to achive this: https://developer.android.com/guide/components/activities/tasks-and-back-stack.html
TL;DR: use flags in the intent to clear the activity back stack.
In the intent:
Intent intent = new Intent(this, YourActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish(); // call this to finish the previous activity
You can try my code :
private static long back_press;
#Override
public void onBackPressed() {
if (back_press + 2000 > System.currentTimeMillis()) {
super.onBackPressed();
} else {
Toast.makeText(getBaseContext(), "Please press again to exit!",
Toast.LENGTH_SHORT).show();
back_press = System.currentTimeMillis();
}
}
It worked for me, i hope it will help you.
Please, take a look at this sample app: https://github.com/IvanShafran/android-stackoverflow/tree/master/BackButtonHandle
Main point is:
private boolean mIsBackButtonPressedBefore = false
#Override
public void onBackPressed() {
if (mIsBackButtonPressedBefore) {
Toast.makeText(this, "Second back button press", Toast.LENGTH_SHORT).show();
super.onBackPressed();
} else {
mIsBackButtonPressedBefore = true;
Toast.makeText(this, "First back button press", Toast.LENGTH_SHORT).show();
}
}
It has described behaviour as you can see at the gif below:
If your code is similar to this but doesn't work you should look for a problem outside of this scope.
I have a Log in screen and on the log in screen i would like so that if you press the back button once nothing happens but if you press it a second time the app stops/exits, i have seen other questions on here but for me non of the solutions work ...
Any help would be appreciated thank you!
This is an attempt of mine however it doesnt exit on the second press it restarts the app and then when you click back twice again from this it then exits ... ;
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
Try this one:
private static long sayBackPress;
#Override
public void onBackPressed() {
if (sayBackPress + 2000 > System.currentTimeMillis()){
super.onBackPressed();
}
else{
Toast.makeText(MainActivity.this, "Press once again to exit!", Toast.LENGTH_SHORT).show();
sayBackPress = System.currentTimeMillis();
}
}
I am trying to release heap size by destroying the current activity, while going to another activity.
I am using finish(); on backPreess()
But this is not releasing the heap.
on setContentView()
The heap size increases 16Mb. I want to release this increase in the heap after going to another activity. Can any one help how to do this?
My code is as following:
package com.stancil.levels;
public class PaintActivity extends ZebraActivity implements
PaintView.LifecycleListener, PaintView1.LifecycleListener1 {
private static final int REQUEST_PICK_COLOR = 1;
....
....
public PaintActivity() {
_state = new State();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Constants.context = getApplicationContext();
setContentView(R.layout.paint);
..................
...................
...............
}
public void onPreparedToLoad() {
// We need to invoke InitPaintView in a callback otherwise
// the visibility changes do not seem to be effective.
new Handler() {
#Override
public void handleMessage(Message m) {
new InitPaintView();
Log.v("PaintActivity", "After InitPaintView Called");
}
}.sendEmptyMessage(0);
}
private class InitPaintView implements Runnable {
private Bitmap _originalOutlineBitmap;
private Handler _handler;
public InitPaintView() {
// Make the progress bar visible and hide the view
_paintView.setVisibility(View.GONE);
_progressBar.setProgress(0);
_progressBar.setVisibility(View.VISIBLE);
_state._savedImageUri = null;
_state._loadInProgress = true;
_originalOutlineBitmap=_imageBitmap;
_handler = new Handler() {
#Override
public void handleMessage(Message m) {
switch (m.what) {
case Progress.MESSAGE_INCREMENT_PROGRESS:
// Update progress bar.
_progressBar.incrementProgressBy(m.arg1);
break;
case Progress.MESSAGE_DONE_OK:
case Progress.MESSAGE_DONE_ERROR:
// We are done, hide the progress bar
// the paint view back on.
_state._loadInProgress = false;
_paintView.setVisibility(View.VISIBLE);
_progressBar.setVisibility(View.GONE);
initiatePopupWindow();
break;
}
}
};
new Thread(this).start();
}
public void run() {
Log.v("Wasimmmmmmmmmmmmmmmm", "qqqqq 22");
_paintView.loadFromBitmap(_originalOutlineBitmap, _handler);
}
}
private static class State {
// Are we just loading a new outline?
public boolean _loadInProgress;
// The resource ID of the outline we are coloring.
//public int _loadedResourceId;
//
// If we have already saved a copy of the image, we store the URI here
// so that we can delete the previous version when saved again.
public Uri _savedImageUri;
}
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Exit")
.setMessage("Do you want to go to Main Menu?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
Constants.check_new=true;
Intent i=new Intent(PaintActivity.this,MainActivity.class);
// i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
finish();
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
}).setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
}
}
release yoru objects in onDestroy method, anyways, if there are no references to the detroyed activity, GC will automaticly clean up whenever its needed (it doesnt need to happen right after you closed your activity).
Alternatively theres a method to force running GC, but I wont even write about it cuz its not really a feature a typical application should use
The dialog:
public class ClearDialog extends Dialog {
private MainActivity context;
public ClearDialog(MainActivity context) {
super(context);
this.context = context;
setContentView(R.layout.clear_dialog);
setTitle("something");
setCanceledOnTouchOutside(false);
setCancelable(true);
}
/* not overriding anymore
#Override
public void onBackPressed() {
return;
}
still doesnt work */
#Override
protected void onStart() {
super.onStart();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.clear();
editor.commit();
ResourceHelpers.removeAllResources();
context.onResourcesDeleted();
}
}
The Activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemLogoff:
loginDialog.show(); //this is another dialog
break;
case R.id.itemSync:
Intent syncer = new Intent(MainActivity.this, SyncActivity.class);
MainActivity.this.startActivity(syncer);
break;
case R.id.itemClear:
new AlertDialog.Builder(this)
.setIcon(R.drawable.ic_action_alert)
.setTitle("something")
.setMessage("something")
.setPositiveButton("something", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
showDeleteDialog();
}
})
.setNegativeButton("something", null)
.show();
break;
}
return true;
}
private void showDeleteDialog() {
cd = new ClearDialog(this); //this is the dialog
cd.show();
}
public void onResourcesDeleted() {
cd.dismiss();
loginDialog.show();
}
So.. The user clicks on "Delete all data" from the ActionBar (optionsmenu). I open an AlertDialog asking if he's sure. Then if he's sure, I open a dialog that shows a spinning ProgressBar.
The problem: it won't dismiss!
The loginDialog (all data is lost so I want the user to login again...) comes up in the background. The ClearDialog won't dismiss...
I think that the problem is here (don't override in this way that method):
#Override
public void onBackPressed() {
return;
}
You can already obtain a modal dialog with .setCancelable(false)
Please take a loog at this documentation: http://developer.android.com/guide/topics/ui/dialogs.html#AlertDialog
Give the following property for dialogue
.setCancelable(true);
its just like .setTitle() or .setMessage in your code....
On top of StErMi's answer, which you should follow, also switch the two lines in your onResourcesDeleted() method. The login dialog is called, and takes over before your dismiss is called.
public void onResourcesDeleted() {
cd.dismiss();
loginDialog.show();
}