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
Related
I have added a popup activity inside my app which is popping after 15 seconds of my app start. But when I am opening another activity and coming back to my main activity the popup showing again. I want it to appear only the first time when user is opening the app. What changes I should make? Appreciate the help.
Here is the popup code:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (context != null) {
AlertDialog.Builder alert = new AlertDialog.Builder(context, R.style.MyAlertDialogStyle)
.setTitle("Title")
.setMessage("Message")
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
Intent intent = new Intent(MainActivity.this, WebActivity.class);
startActivity(intent);
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int which) {
dialogInterface.dismiss();
// do nothing
}
});
mDialog = alert.create();
mDialog.getWindow().getAttributes().windowAnimations = R.style.MyAlertDialogStyle;
if (!((Activity) context).isFinishing())
mDialog.show();
// .setIcon(R.drawable.inr1)
// .show();
}
}
}, 15000);
You can do this if it needs to pop up only on application start
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
//Set some flag on global constant
}
}
save a tag(counter) in sharedPrefrances for that When the application starts up interpretation is the first time app start
You can use a global variable in the application class like this.
public class global extends Application
// some Boolean variable to hold status
And make sure you put this class inside android manifests application tag
android:name
Add this code in your MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if(sharedPreferences.getBoolean("IS_FIRST_TIME", true)) {
//show your dialog here
//...
//change the value of your sharedPreferences
sharedPreferences.edit().putBoolean("IS_FIRST_TIME", false).apply();
}
}
please check the activity lifecycle.
Note:Remove Handler.
Note 2:Create method and call the dialog
Note 3:check the below method in lifecycle.
onPause ():
Called as part of the activity lifecycle when an activity is going into the background, but has not (yet) been killed. The counterpart to onResume(). When activity B is launched in front of activity A, this callback will be invoked on A. B will not be created until A's onPause() returns, so be sure to not do anything lengthy here.
save a boolean inside sharedpreferences read its value and determine weather running for the first time or not.
here is the code that will help you.
public void firstimeRun(boolean value) {
SharedPreferences sharedPreferences = getPrefrenceManager();
sharedPreferences.edit().putBoolean("key", value).apply();
}
public boolean isRunningForthefirstTime() {
SharedPreferences sharedPreferences = getPrefrenceManager();
return sharedPreferences.getBoolean("key", false);
}
private SharedPreferences getPrefrenceManager() {
return PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
}
Type finish(); after your startActivity(intent);
I have used code below:
AlertDialog.Builder bld;
if (android.os.Build.VERSION.SDK_INT <= 10) {
//With default theme looks perfect:
bld = new AlertDialog.Builder(AndroidLauncher.this);
} else {
//With Holo theme appears the double Dialog:
bld = new AlertDialog.Builder(AndroidLauncher.this, android.R.style.Theme_Holo_Dialog_MinWidth);
}
bld.setIcon(R.drawable.ic_launcher);
bld.setTitle("Exit");
bld.setMessage("Are you sure you want to exit?");
bld.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); }
});
bld.setPositiveButton("Exit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) { finish(); }
});
bld.setCancelable(false);
bld.create().show();
It seems fine, but it says "import android.app.AlertDialog cannot resolve".
It is a standard libGDX project in Android Studio.
In libgdx you should use a scene2d dialog instead of the native Android DialogInterface. Below is how you would add a completely skinned dialog to the stage in libgdx with custom button images and background image. You would just need to substitute your own background and button image textures and font, then call quitGameConfirm() when you're ready to display the dialog...
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
public void quitGameConfirm() {
LabelStyle style = new LabelStyle(_fontChat, Color.WHITE);
Label label1 = new Label("Are you sure that you want to exit?", style);
label1.setAlignment(Align.center);
//style.font.setScale(1, -1);
style.fontColor = Color.WHITE;
Skin tileSkin = new Skin();
Texture tex = new Texture(myButtontexture);
tex.setFilter(TextureFilter.Linear, TextureFilter.Linear);
tileSkin.add("white", tex);
tileSkin.add("default", new BitmapFont());
TextButton.TextButtonStyle textButtonStyle = new TextButton.TextButtonStyle();
textButtonStyle.up = tileSkin.newDrawable("white");
textButtonStyle.down = tileSkin.newDrawable("white", Color.DARK_GRAY);
textButtonStyle.checked = tileSkin.newDrawable("white",
Color.LIGHT_GRAY);
textButtonStyle.over = tileSkin.newDrawable("white", Color.LIGHT_GRAY);
textButtonStyle.font = _myTextBitmapFont;
textButtonStyle.font.setScale(1, -1);
textButtonStyle.fontColor = Color.WHITE;
tileSkin.add("default", textButtonStyle);
TextButton btnYes = new TextButton("Exit", tileSkin);
TextButton btnNo = new TextButton("Cancel", tileSkin);
// /////////////////
Skin skinDialog = new Skin(Gdx.files.internal("data/uiskin.json"));
final Dialog dialog = new Dialog("", skinDialog) {
#Override
public float getPrefWidth() {
// force dialog width
// return Gdx.graphics.getWidth() / 2;
return 700f;
}
#Override
public float getPrefHeight() {
// force dialog height
// return Gdx.graphics.getWidth() / 2;
return 400f;
}
};
dialog.setModal(true);
dialog.setMovable(false);
dialog.setResizable(false);
btnYes.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
// Do whatever here for exit button
_parent.changeState("StateMenu");
dialog.hide();
dialog.cancel();
dialog.remove();
return true;
}
});
btnNo.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y,
int pointer, int button) {
//Do whatever here for cancel
dialog.cancel();
dialog.hide();
return true;
}
});
TextureRegion myTex = new TextureRegion(_dialogBackgroundTextureRegion);
myTex.flip(false, true);
myTex.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
Drawable drawable = new TextureRegionDrawable(myTex);
dialog.setBackground(drawable);
float btnSize = 80f;
Table t = new Table();
// t.debug();
dialog.getContentTable().add(label1).padTop(40f);
t.add(btnYes).width(btnSize).height(btnSize);
t.add(btnNo).width(btnSize).height(btnSize);
dialog.getButtonTable().add(t).center().padBottom(80f);
dialog.show(stage).setPosition(
(MyGame.VIRTUAL_WIDTH / 2) - (720 / 2),
(MyGame.VIRTUAL_HEIGHT) - (MyGame.VIRTUAL_HEIGHT - 40));
dialog.setName("quitDialog");
stage.addActor(dialog);
}
The problem is that you are trying to create an Android widget which I suspect you are doing it in the Libgdx-core implementation. The core implementation does not have any references to Android SDK.
That is because it is the Android project which inherits the core project. As a result the core project is not aware of any dependencies loaded to the Android implementation.
To overcome this you need to create an interface between Android project and Core Project. That will allow you to call methods inside the Android Project.
The interface must be created inside the core Project in order for both projects to have access to it.
For example you create CrossPlatformInterface.java inside core Project. But first let's create a callback to get feedback from the Ui Thread inside the Libgdx Thread. It is important to remember that Libgdx has a seperate thread that Android main thread!!! If you try to run Widgets of Android from Libgdx threads the Application will crush.
Let's make the callback for the AlertDialog. I will suggest an Abstract class here in order to be able to override only the methods you want because sometimes Alertdialog can have 1,2 or 3 buttons.
In Core Project create AlertDialogCallback.java:
public abstract class AlertDialogCallback{
public abstract void positiveButtonPressed();
public void negativeButtonPressed(){}; // This will not be required
public void cancelled(){}; // This will not be required
}
In Core Project also create CrossPlatformInterface.java:
public interface CrossPlatformInterface{
public void showAlertDialog(AlertDialogCallback callback);
}
You notice that in the showAlertDialog method we pass the callback to get feedback when buttons are pressed!
Then you create a Class inside Android project that will implement the CrossPlatformInterface like:
public ClassInsideAndroidProject implements CrossPlatFormInterface{
private AndroidLauncher mActivity; // This is the main android activity
public ClassInsideAndroidProject(AndroidLauncher mActivity){
this.mActivity = mActivity;
}
public void showAlertDialog(final AlertDialogCallback callback){
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle("Test");
builder.setMessage("Testing");
builder.setPositiveButton("OKAY", new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
callback.positiveButtonPressed();
}
});
builder.setNegativeButton(negativeButtonString, new OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which) {
callback.negativeButtonPressed();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
});
}
}
Important notes
The CrossPlatformInterface will be instantiated inside the MainActivity (AndroidLauncher) as you will see below.
The AlertDialog will be created inside the android UI thread. Because we are coming from the Libgdx thread to create the AlertDialog we need to use runOnUiThread to ensure the AlertDialog is created in ui thread.
Finally how to execute this:
Instantiate CrossPlatform interface inside Android main Activity and pass the Activity to the Interface instance which is passed inside the MyGdxGame:
public class MainActivity extends AndroidApplication {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration cfg = new AndroidApplicationConfiguration();
cfg.useGL20 = false;
initialize(new MyGdxGame(new ClassInsideAndroidProject(this)), cfg);
}
}
Finally when the MyGDxGame is created we get the instance of the crossplatform interface and we can the call any functions we want to the android ui thread.
public class MyGdxGame extends Game {
ClassInsideAndroidProject crossPlatformInterface;
public MyGdxGame(ClassInsideAndroidProject crossPlatformInterface){
this.crossPlatformInterface = crossPlatformInterface;
}
#Override
public void create() {
crossPlatformInterface.showAlertDialog(new AlertDialogCallback(){
#Override
public void positiveButtonPressed(){
//IMPORTANT TO RUN inside this method the callback from the ui thread because we want everything now to run on libgdx thread! this method ensures that.
Gdx.app.postRunnable(new Runnable().....)
}
#Override
public void negativeButtonPressed(){
}; // This will not be required
#Override
public void cancelled(){
}; // This will not be required
});
}
#Override
public void render() {
super.render();
}
public void dispose() {
super.dispose();
}
public void pause() {
super.pause();
}
}
I think it was much more writing I first intended. It might look daunting but actually is fairly simple. Well after you've done it everything looks simpler :).
The advantage of this effort is after you make this interface any call to android widget will be very easy and thread safe.
Hope it gives a good picture.
This works (tested). Simply pass in the FragmentActivity or Activity
via your game constructor. You have to pass something in (like
ClassInsideAndroidProject). Why not pass in a really useful element !.
//---------------------------------------------------------------------------
/** INSIDE the libgdc core, create a custom NATIVE android dialog
* :- breaks the rules somewhat for the core,
* but if you ONLY using Android, why not use android Native!
* #member_var private final FragmentActivity m_fa;
* #constructor public xx_your_app_xx(FragmentActivity m_fa)
*{
* this.m_fa = m_fa;
*}
* #called_with if(m_fa != null) showCustomDialog(m_fa);
* #param fa
*/
public static void showCustomDialog(final FragmentActivity fa) //or Activity
{
fa.runOnUiThread(new Runnable()
{
// boolean[] info;
#Override
public void run()
{
LinearLayout ll_Main = new LinearLayout(fa);
LinearLayout ll_Row01 = new LinearLayout(fa);
LinearLayout ll_Row02 = new LinearLayout(fa);
LinearLayout ll_Row09 = new LinearLayout(fa);
LinearLayout ll_Row10 = new LinearLayout(fa);
ll_Main.setOrientation(LinearLayout.VERTICAL);
ll_Row01.setOrientation(LinearLayout.HORIZONTAL);
ll_Row02.setOrientation(LinearLayout.HORIZONTAL);
ll_Row09.setOrientation(LinearLayout.HORIZONTAL);
ll_Row10.setOrientation(LinearLayout.HORIZONTAL);
final CheckBox checkBox = new CheckBox(fa);
final CheckBox cb_debug = new CheckBox(fa);
final EditText et_User = new EditText(fa);
final EditText et_Pass = new EditText(fa);
TextView tv_Check = new TextView(fa);
TextView tv_Debug = new TextView(fa);
TextView tv_User = new TextView(fa);
TextView tv_Pass = new TextView(fa);
tv_Check.setText("rotation lock: ");
tv_Debug.setText("debug: ");
tv_User.setText("Username: ");
tv_Pass.setText("Password: ");
ll_Row01.addView(tv_Check);
ll_Row01.addView(checkBox);
ll_Row02.addView(tv_Debug);
ll_Row02.addView(cb_debug);
ll_Row09.addView(tv_User);
ll_Row09.addView(et_User);
ll_Row10.addView(tv_Pass);
ll_Row10.addView(et_Pass);
ll_Main.addView(ll_Row01);
ll_Main.addView(ll_Row02);
// ll_Main.addView(ll_Row09);
// ll_Main.addView(ll_Row10);
AlertDialog.Builder alert = new AlertDialog.Builder(fa);//this.getActivity()
alert.setTitle("Camera settings");
alert.setView(ll_Main);
alert.setCancelable(false);
alert.setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
// info1[0] = checkBox.isChecked();
// info1[1] = cb_debug.isChecked();
// String user = et_User.getText().toString();
// String pass = et_Pass.getText().toString();
//do something with the data
Gdx.app.log("INFO", "**** positiveButtonPressed works here too! ***");
Toast.makeText(fa,
"checkBox: " + checkBox.isChecked() +
", cb_debug: " + cb_debug.isChecked(),
Toast.LENGTH_LONG).show();
//IMPORTANT TO RUN inside this {} means everything now run's on libgdx thread!.
Gdx.app.postRunnable( new Runnable()
{
public void run()
{
//do something with the data
Gdx.app.log("INFO", "**** positiveButtonPressed works here ****");
}//run
});//postRunnable
}//onClick
});//setPositiveButton
alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}//setPositiveButton
});//setNegativeButton
AlertDialog dialog = alert.create();
dialog.show();
}//run
});//runOnUiThread
}//showCustomDialog
//--------------------------------------------------------------------------------
Before referring me to other threads on this forum and marking my question as duplicate kindly read my question. I have to create a global application timeout. No matter which activity is user on, after specific amount of time the user will be displayed AlertDialog that his session has expired and he can exit or renew his session. I have read different solutions and used service as my solution.
public class InActivityTimer extends Service {
MyCounter timer;
#Override
public void onCreate() {
timer = new MyCounter(20 * 1000,1000);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
timer.start();
return super.onStartCommand(intent, flags, startId);
}
private class MyCounter extends CountDownTimer{
public MyCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
Intent intent = new Intent("timeout_action");
sendBroadcast(intent);
stopSelf();
}
#Override
public void onTick(long millisUntilFinished) {
// Need AlertDialog code here
Toast.makeText(getApplicationContext(), ("Time Remaining: " + millisUntilFinished/1000)+"", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDestroy() {
timer.cancel();
super.onDestroy();
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
The problem is that I can display the Toast without any problem but the AlertDialog is not displayed when called inside onFinish().
The first problem is to display the AlertDialog for whole application bearing in mind that the AlertDialog is displayed for some context. Also if somehow the AlertDialog is displayed then how to close the Application. On Activity I just close the activity by calling finish() so should I clear the Activities stack in this case?
The second complex part that I am facing is to display a popup when user click "Time remaining" link in the application which will show how much time is remaining for the Session to be timed out. This time should be exactly same as the time remaining in the service.
I can also use BroadcastReceiver and send update to the activity once the time is finished but wouldn't that be Activity specific because I want the timeout to act same regardless of which activity is user on. I want to avoid writing the same code on each activity.
Kindly guide me through with some solution.
If you use a fragment based design for your app, you can keep a root FragmentActivity in which all other elements of the app are displayed. This way you can use the context of the root FragmentActivity every time, to display your Dialog.
Additional: "Could you kindly refer to me some article.."
What you are doing is not common, and I would have to google search just like you to find any existing example similar to your case. I can however fill in a bit more detail on what I have proposed above.
If you are unfamiliar with using Fragments, read the Developer Documentation.
public class MainActivity extends FragmentActivity {
private static final int SPLASH_SCREEN_FRAGMENT = 0;
private static final int HOME_SCREEN_FRAGMENT = 1;
...
#Override
protected void onCreate(Bundle. savedInstanceState) {
super.onCreate(savedInstanceState);
// show your first fragment
Fragment splashFragment = new SplashFragment();
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, splashFragment).commit();
// Start your service using the context of your FragmentActivity
// Your FragmentActivity will always be the current activity, and you will display
// all other elements of your app inside it as fragments
Intent intent = new Intent(this, InActivityTimer.class);
startService(intent);
}
// method for switching the displayed fragment
private void fragmentSwitcher(int fragmentType) {
Fragment currentFragment = new Fragment();
switch (currentFragmentType) {
case SPLASH_SCREEN_FRAGMENT:
currentFragment = new SplashScreenFragment();
break;
case HOME_SCREEN_FRAGMENT:
currentFragment = new HomeScreenFragment();
break;
...
}
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, currentFragment).commit();
}
}
I have solved my issue with rather very simple approach.
#Override
public void onFinish() {
Intent intent = new Intent(getBaseContext(), TimeoutActivity.class);
startActivity(intent);
stopSelf();
}
and below is the onCreate method for my TimeoutActivity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContextThemeWrapper ctw = new ContextThemeWrapper(TimeoutDialogActivity.this, R.style.Theme_Base_AppCompat_Dialog_FixedSize);
final AlertDialog alertDialog = new AlertDialog.Builder(ctw).create();
alertDialog.setCancelable(false);
alertDialog.setTitle("Session Timeout !");
alertDialog.setTitle("Your session has expired.");
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Logout", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Exit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
}
});
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Renew Session", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
});
alertDialog.show();
}
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();
}
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();
}
}