Is it possible to know if the app is starting after the user has force quit through settings?

StackOverflow https://stackoverflow.com/questions/9400488

  •  29-10-2019
  •  | 
  •  

Question

I want to know, probably in onCreate() of my activity, if the app was previously closed as per the normal home/back button or if the user actually went into the Android settings and selected force close.

Is it possible to distinguish these two cases?

EDIT:

I think I might not have explained what I mean well enough. I've read the activity lifecycle document and I understand that fairly well.

Basically, I just want to know when the activity is created, whether or not the user has previously gone into the Android settings and hit force stop. If the app was force stopped, I want to take an action (specifically, display the splash screen on startup).

Lots of the answers below say that I can put a flag in onStop() or onDestroy(), and that these methods won't be called if the user hits force stop. The problem is that these methods would have ALREADY been called before getting to that point, because of this sequence:

  1. app is in the active state, being used
  2. User hits back button (onStop(), onDestroy() called), or home button (onStop() called), or recent apps button (onStop() called)
  3. user goes into android settings, taps force stop

In that situation, I will have put the flag into shared preferences on onStop(), but then the user hits force stop and the flag is still active in onCreate().

I don't want to display the splash screen unless the user has hit force stop in settings. I know this is not the way it should be done... but this decision was not made by me.

Was it helpful?

Solution

I ran into same issue yesterday and this is what I found stated by Mark Murphy. But I have managed to crack it.

Actually,whenever "Force Stop" is pressed,the system will clear all the memory occupied by the application except 2 things.

1:the shared preference and 2:sqlite database.

So I have done the trick by storing a boolean variable in application,manipulating the value and then check it on each start up of application.and it's done.

CONSTANTS.java

package com.mehuljoisar.forcestopdemo;

public class CONSTANTS {

//the changes made to value of below variable will be cleared on force stop,so whenever force stop occurs,the value of variable will be "isForceStopped=true" again.
    public static boolean isForceStopped = true;
}

MainActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

    private Context mContext;
    private Intent i;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initialize();


        if(CONSTANTS.isForceStopped)
        {
        //this block of code will be executed in 2 scenario,
        //1: when application is started for very first time
        //2: when application is started after force stopping
            Toast.makeText(mContext, "Display Splash-screen and move to next screen", Toast.LENGTH_SHORT).show();
        //don't forget this part,it's important to make change so that next time splash screen can be avoided
             CONSTANTS.isForceStopped=false;

        //and then launch next screen
            launchSecondScreen();
        }
        else
        {
        //directly launch next screen
            launchSecondScreen();
        }
    }

    private void launchSecondScreen() {
        i.setClass(mContext, SecondActivity.class);
        startActivity(i);
        finish();
    }

    private void initialize() {
        mContext = this;
        i = new Intent();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

SecondActivity.java

package com.mehuljoisar.forcestopdemo;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

}

AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mehuljoisar.forcestopdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.mehuljoisar.forcestopdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.mehuljoisar.forcestopdemo.SecondActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

I hope it will be helpful !!

OTHER TIPS

I'm not sure if there is an easier way but you could create a SharedPreferences object that is updated with a flag in the onStop function of the Activity. And check for the flag in the onCreate. I don't think the onStop or onDestroy is called if the user force closes the app.

If the user closed your application with "force close" the "onStop" method doesn't execute. You may put a flag (like saving in a file, user preferences, sql etc) in that method. Next time the application starts, check that flag!

Override the onBackButtonPressed in your Home activity(in normal case when with back button the application main activity is closed).

set a variable(say, lastforceClose as false) SharedPreferences in this function and then call super method of onbackbuttonpressed() or finish() to finish off activity.

Next time whenever you start the activity you can check out for the variable in the sharedpreferences to see lastforceClose variable if it is either set to false or not ( and you yourself change it to true now)...

You might also want to handle case here when user has deleted data through android settings.. (i.e. key not present in shared preferences xml file etc.)

I am not 100% sure but this should work.
1) Save state (Normal shutdown) in onDestroy of the Activity on some persistent storage. (SharedPreferences or SQLite)
2) in onCreate check for the state, if it is normal shutdown then app was closed normally else it was force closed. reset the state.

First, it sounds like you might be confusing resuming with creating. Definitely read through the App fundamentals, specifically the stuff about Activity Lifecycle. That state diagram is helpful.

When a user "backs" out of an Application, it is not necessarily destroyed. In fact, it probably isn't destroyed unless the dev puts some hooks in the onPause() that explicitly destroys the Activity.

The single most important concept in Android App lifecycles to understand is this:

The Android OS makes absolutely no guarantee about how long your application will be alive, except for the guarantee that it can die at any time whether you want it to or not.

You should always write your app accordingly, and it is good practice to populate every single one of the lifecycle start up and wind down hooks. When a user does a hardware button back out from your app, then the app is not necessarily destroyed, but when the app is closed out via force quitting then it is absolutely destroyed. Instead of trying to finagle your way in to figuring out how the app was closed, the "proper" way to handle this is to have your onPause(), onStop(), and onDestroy() methods set up to do the appropriate amount of cleaning up based on the state of the activity, and maybe have some sort of Preference object or state variable that only gets flipped if onDestroy() is called, since technically the OS can still "force quit" the app for you even if the user doesn't do so via the task manager.

You might try persisting a record of all app lifecycle events and then checking in your various onCreate()s whether the last event recorded was normal. If not, you could reasonably infer that something happened. I'm guessing that any force close invoked by the user simply results in the system sending a kill(2) to the app, in which case you won't receive any indication. This might help.

You might also consider whether you can achieve what you're after in a different way. If your app is entirely stateless, then there shouldn't be a problem with shutdowns of any kind. If your app has state then in theory all of your data/app transactions can achieve ACIDity, and so you can avoid inconsistencies due to crashes/force closes.

Does that help or are you after something else?

What about writing status flags from a service, not an activity? The activity lifecycle will still complete, but the service lifecycle shouldn't.

It's not identical to your requirement, but it might be close enough. You'd want to stop the service (and restart later) if you're showing an activity that doesn't have this requirement. Or just have the service write an event stream of some sort and use that to figure out what to show on startup.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top