I have an app that has a lot of activities. In the "Settings" page there is a delete account button that is supposed to reset all the saved variables and exit the app. I haven't found a simple solution to exiting the app (eg calling finish only destroys the current activity) What do I call to close the app on a button press (eg when I reopen the the app it should start from the first activity)
Easiest way to do this is to register a BroadcastReceiver in all Activity classes that listens for a specific Intent. When you want to close everything then just fire the matching Intent, and in the BroadcastReceiver in each Activity call finish.
Try System.exit(0), although you're technically suppose to use finish() on all the activities. This does the same, but quickly.
Use this:
Process.killProcess(Process.myPid());
Or there is another more safer approach. Just subclass all of your activities, from one parent Activity and keep list of all alive activities and then when necessary close them all using exit():
public class ControlActivity extends Activity
{
private static ArrayList<Activity> activities=new ArrayList<Activity>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activities.add(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
activities.remove(this);
if(activities.size()==0) //last activity
//release resources and so on
}
//close all activities, when necessary
public static void exit()
{
for(Activity activity:activities)
activity.finish();
}
}
Related
I'm trying to determine when my app is being resumed after the user closed it, in any way, pressing home button, back button or switching to another app.
What I need to do is to set a boolean when the app goes in background, so, when it is resumed, I know that it was in background before and I can act accordingly.
I tried to use onResume and onPause methods in activities to know when the app goes in background and it is then resumed, but as only one activity can be alive at at time, I had no success. When an activity is paused, this doesn't mean that the app went to background, because another activity could have been launched, but the onResume event of that activity will trigger only after the previous one has paused.
I've also tried to list all the apps in foreground, but with no success, if I put my app in background resuming another app, my app always results to be in the foreground.
I read that since Android 4 there is a new method to know when the app is in foreground, but I need my app to be compatible with Android 3.0 devices too.
Here is the code I tried putting in every single activity (MyApp is my Application name):
#Override
protected void onResume() {
super.onResume();
MyApp.isPaused = false;
}
#Override
protected void onPause() {
super.onPause();
MyApp.isPaused = true;
}
This is also my attempt to list all the apps in foreground:
ActivityManager activityManager = (ActivityManager)((Activity) currentContext).getSystemService( ACTIVITY_SERVICE );
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
for(RunningAppProcessInfo appProcess : appProcesses){
if(appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
if(appProcess.processName.equals("com.xxx.myapp")) {
Log.i("MyApp", "it's in foreground");
}
Log.i("MyApp", appProcess.processName);
}
}
This class provides a singleton to determine "the activity in background" status. It uses a timer with a threshold(i.e. 0.3s) to determine the activity is went to background or not.
One thing has to point out is that if the user resumes to the activity within the threshold (i.e. 0.3s), this test will be failed.
If you have a better solution, please share with us :)
Ref: https://gist.github.com/steveliles/11116937
You are absolutely correct :) Because only one activity can be alive at a time so you need something which remains alive through out the application life cycle :) like Application instance itself or you can also make use of shared preference for that matter. But seriously using shared prefference for checking lifecycle is wrong choice if you ask me.
If I was in your position I would have gone for Application class :) Here is code if you want to do the same :)
import android.app.Application;
/**
* Created by sandeepbhandari on 3/3/16.
*/
public class AppService extends Application{
private static AppService sInstance;
public static boolean isGoingToBackGround=false;
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static AppService getInstance() {
return sInstance;
}
}
In all your activities onPause just set
AppService service = AppService.getInstance();
service.isGoingToBackGround =true;
And in onResume check the same variablethats all :) and yeah if you want to use your application class rather than default Application you have to make change to manifest.xml
<application
android:name=".AppService"
Thats all :)
Override onTrimMemory(int level) in your Application. Might not be the prettiest way, but it has worked for me.
You will get
TRIM_MEMORY_BACKGROUND = 40;
when your application went into the Background.
You can make Application class inside your project to save state of your project. When any activity goes to pause call on pause respectively while on resume call on resume method and save state of the inside this class. Even if one activity goes on pause another on resume your class will know exact state of the application. Or another way you can save applicaton state in shared preference in each activity can change its value.
i trust there is no need for u to post a code... that being said...
start by logging every implemented methods onCreate(), onPause(), onDestroy(), and other well reputed Activity methods...
but back button does not just pause it kills, thus onCreate is called most
and check onStart() too.
public class CustomApplication extends Application {
private static boolean activityVisible;
#Override
public void onCreate() {
super.onCreate();
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
}
and in your all activities set
#Override
protected void onResume() {
super.onResume();
CustomApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
CustomApplication.activityPaused();
}
and in your manifest
<application
android:name=".CustomApplication"
by using onResume() i can check if an activity is foreground or not. My problem is this onResume() is fire each time even if i come from another activity to this activity.
So my main problem is ,if i minimizing the app by home button I want execute some code in each activity when app is come foreground BUT not using onResume().
I found an answer like this How to know in BroadcastReceiver if App is running on foreground? but i dont know how to register this receiver in android menifest to get the trigger when app is visible.
Please give me some tips how can i overcome this solution or code snippet which can help me. Thanks in advance :)
One thing to do what you want is to count the number of times onStart/onStop is called in your application. This will help you determine if you transitioned to your activity from inside or outside your application.
You must extend Application then create/register ActivityLifecycleCallbacks within that class. Also, make sure to specify the new Application class you created in the AndroidManifest.
Now, the trick is to keep a count variable in onActivityStarted/onActivityStopped to determine whether your Activity was navigated to from inside or outside the application.
Say you have 2 Activities in your app: FirstActivity & SecondActivity.
If you navigate from FirstActivity to SecondActivity the lifecycle calls will happen in this order: FirstActivity.onStart() > SecondActivity.onStart(), resulting in a count of 1.
If you navigate from outside your application, you will only see FirstActivity.onStart(), so the count is 0. This is all assuming you check the count after super.onStart() is called.
So, by checking count against 0/1 you can tell if your activity was launched from within the application or outside the application.
/**
* Extending the application class lets you use ActivityLifecycleCallbacks to
* keep track of all lifecycle callbacks in your application.
*/
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private int count = 0;
//Register activity lifecycle callbacks in onCreate
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
void onActivityStarted(Activity activity) {
count++;
}
void onActivityStopped(Activity activity) {
count--;
}
/**
* Use this method in your Activities to test if the activity was
* transitioned to from outside the application.
*
* If you call this method in Activity.onResume(), then count should be
* compared to 0. If you call this method in Activity.onStart() but
* *before* calling super.onStart(), then count should be compared to 0.
*
* However, if you call this method after super.onStart(), then count
* should be compared to 1.
*/
public boolean cameFromOutsideApplication() {
return count == 0;
}
//Don't need to use the rest of the activity lifecycle callbacks
void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
void onActivityDestroyed(Activity activity) {
}
void onActivityPaused(Activity activity) {
}
void onActivityResumed(Activity activity) {
}
void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
}
You may gain some more information here as well but it does not use ActivityLifecycleCallbacks which is easier to use.
If you want to register your receiver you can use the following code,
<receiver
android:name="com.package.name.ReceiverClassName"
android:enabled="true" >
</receiver>
I'm trying to make a certain function to start only when a user,
Opens the app for the first time,
Goes back to an app from home.
But not start if the user switches between activities within the app.
I have looked through this topic,and the best answer is to use singleTask with onNewIntent(). So, if a user is goes back to the app from Home, a onNewIntent call with the launcher intent passed to it can be used.
However, here is my code:
public class AdMobSDK_DFP_Interstitial extends Activity implements AdListener {
private static final String MOBMAX_INTERSTITIAL_AD_UNIT_ID = "/7732/test_portal7/android_app1_test_portal7/splash_banner_android_app1_test_portal7";
private DfpInterstitialAd interstitialAd;
private int num = 0;
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
Log.d("flow", "onNewIntent");
}
If I switch between different activities in the app, onNewIntent() is always called, which is the same as I go back to the app from Home.
First thing you can do is to implement your own "Application" object and have it run the needed function when it is created.
public class MyApplication extends Application {
#Override
public void onCreate() {
// Call your function
}
}
Your application object will be live as long as your app is alive (any activity/service is still running), but note that the Application object is not destroyed immediately when the user presses "Home", and might stay alive for a while and a user can return to it without the function being called.
If you need this function to run as part of your main activity, just save a flag in your Application context :
public boolean alreadyDisplayed = false; and then in your activity's onStart you can just call
if ((MyApplication)getApplication().alreadyDisplayed ) {
// Call your function
(MyApplication)getApplication().alreadyDisplayed = true;
}
** If this solution is not enough for you and you need to call your function every time your main activity is displayed from the home page you'll need to do something not as nice... one suggestion I can give you is to implement the same Application object but this time with an "open activity" counter:
public class MyApplication extends Application {
public int mActivityCounter = 0;
}
Then you can increment this counter on every onStart of activity in your app and decrement on every onStop (of course this can be done by implementing a class MyActivity and make all your relevant activities inherit it. Then you can use this counter to know if there are any other activities opened. Note that you'll have to make sure the access to this counter is synchronized and work your way with it as you need.
I hope this helps...
This looks very similar to my previous question because it's some sort of follow up. I was not very happy with the only solution given; also, the solution was for a problem slightly different from this one. So let me try to explain the problem again...
A notification is created at boot (with a BroadcastReceiver).
My app main activity is opened and the home button is pressed (the activity will be sent to the back stack).
I pull down the status bar and press on the notification previously created at boot.
That will start some activity, different from the main one.
I press the back button and the main activity is displayed.
This is not very different from my previous question... The thing is, "main activity" was just an example. I could have opened the app main activity and then opened the about activity through a menu option and pressed the home button. The back stack would now be MainActivity ยป AboutActivity. Which means that when the back button is pressed while in "some activity" (started by pressing the notification), we would be brought to the top of the back stack, that is, the about activity.
What basically want is to prevent any other activity to be opened when I press the back button while in "some activity" (again, started by pressing the notification). I want to be brought exactly where I was, that could be the desktop or some other app's activity, but not my app's MainActivity nor AboutAcitivity cause that's not where I was, those were in the back stack, "sleeping" in the background.
I have come up with a solution, but I don't think it's very elegant and I was looking for something more, well, elegant... If you have any other suggestion, please, let me know.
Anyway, this is my proposed solution:
// I use this class for public static (or public static final) members and
// methods
public final class AppHelper {
public static final String KEY_RESUME_FROM_NOTIFICATION = "resumeFromNotification";
private static boolean sResumeFromNotification = false;
public static boolean getResumeFromNotification() {
return sResumeFromNotification;
}
public static void setResumeFromNotification(boolean resumeFromNotification) {
sResumeFromNotification = resumeFromNotification;
}
}
public class MainActivity extends ListActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class AboutActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
}
#Override
protected void onResume() {
super.onResume();
if(AppHelper.getResumeFromNotification()) {
AppHelper.setResumeFromNotification(false);
moveTaskToBack(true);
}
}
}
public class SomeActivity extends Activity {
// This will be called when the notification is pressed and the activity is
// not opened yet
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
(...)
extractIntentExtras(intent);
}
// This will be called if the activity is already opened and the
// notification is pressed
#Override
protected void onNewIntent(Intent intent) {
extractIntentExtras(intent);
super.onNewIntent(intent);
}
private void extractIntentExtras(Intent intent) {
Bundle bundleExtras = intent.getExtras();
if(bundleExtras != null) {
// These intent extras are set on the Intent that starts this activity
// when the notification is pressed
AppHelper.setResumeFromNotification(bundleExtras.getBoolean(
AppHelper.KEY_RESUME_FROM_NOTIFICATION));
mRowId = bundleExtras.getLong(AgendaNotesAdapter.KEY_ROW_ID);
populateNoteUpdateFields();
}
}
}
I don't know, but this solution doesn't look very elegant to me (but it works as I expect it) and I'm looking for alternatives or for strong opinions on my proposed solution as an acceptable and good solution. Thoughts?
After doing some more reading perhaps this is the combination of flags you need:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
I think that should force your SomeActivity class to be launched in a completely new task.
When launching the Activity from the notification, you can control how the Activity you are about to open is put on the back stack, and what task it's associated with with Intent flags. You can try something like:
Intent intent = new Intent(mContext, SomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
If that doesn't work, try setting a few of the other flags until you get the desired behavior.
Do you ever want your MainActivity to stay in history? If not then my simple, crude solution is to finish the MainActivity when it is paused.
(Call this in your MainActivity)
#Override
public void onPause() {
finish();
}
This will ensure that your MainActivity is removed from history when you navigate away from it, and will never appear when the back button is pressed.
This could be used for AboutActivity as well.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Quitting an application - is that frowned upon?
I've written an android app, that has 5 activities. Each activity is started by the activity before it.
When the user gets to the last activity, i have added an "EXIT" button.
When this button is pressed, i call finish();
However this only closes the current activity, and the app returns to the previous activity.
Is there an easy way to terminate all activities when exit button is pressed.
thanks
Usually it is not a good idea to add "exit" feature to an app. That's not in Android nature. Read the topic first.
If you don't care about the last opened activity, then call finish on each activity just after you call startActivity calling the next one.
If you do care, and just want to kill'em all when you click the Exit button on the last activity, then use BroadcastReceivers:
Create a BaseActivity like this:
public class BaseActivity extends Activity {
private KillReceiver mKillReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mKillReceiver = new KillReceiver();
registerReceiver(mKillReceiver,
IntentFilter.create("kill", "spartan!!!"));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mKillReceiver);
}
private final class KillReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
}
}
Make your activities extend that BaseActivity.
Whenever you want to clear the stack:
Intent intent = new Intent("kill");
intent.setType("spartan!!!");
sendBroadcast(intent);
catch this result in onActivityResult() and then just propagate it through the stack?
Do not add an exit button. It almost never makes sense in the Android world. Read this article by a Google employee for some valuable insight why.