131

I am currently developing an android app. I need to do something when the app is launched for the first time, i.e. the code only runs on the first time the program is launched.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
Boardy
  • 35,417
  • 104
  • 256
  • 447
  • 2
    When I first started making apps, I was only thinking about the first run after an app is installed. I later realized that I also needed to handle and differentiate first runs after upgrades. @schnatterer's answer below and my answer [here](http://stackoverflow.com/a/30274315/3681880) show how to do this. Be cautious of answers that don't take upgrades into account. – Suragch Jul 22 '15 at 16:25
  • @Suragch you're acting like it is bad practice to not take upgrades into account but in some cases like having an app introduction you DON'T want to do it :) – creativecreatorormaybenot Sep 12 '16 at 17:59
  • @creativecreatorormaybenot, that's true. There are times when you only care about the initial install and not subsequent upgrades. A simple boolean is enough for those situations. However, what if at some time in the future you want to add a different introduction for current users about all the new features you just added in the last update? In my opinion it is more far-sighted to check the version number rather than a boolean. This at least gives you the option in the future to respond one way for a new install and another way for an upgrade. – Suragch Sep 13 '16 at 01:45
  • 1
    Then you just add it for this version but I get yoz – creativecreatorormaybenot Sep 13 '16 at 05:15
  • You can check this https://stackoverflow.com/a/7217834/2689076 – Vaibhav Oct 04 '19 at 04:31

16 Answers16

125

You can use the SharedPreferences to identify if it is the "First time" the app is launched. Just use a Boolean variable ("my_first_time") and change its value to false when your task for "first time" is over.

This is my code to catch the first time you open the app:

final String PREFS_NAME = "MyPrefsFile";

SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

if (settings.getBoolean("my_first_time", true)) {
    //the app is being launched for first time, do something        
    Log.d("Comments", "First time");

             // first time task

    // record the fact that the app has been started at least once
    settings.edit().putBoolean("my_first_time", false).commit(); 
}
harrakiss
  • 1,617
  • 2
  • 14
  • 13
  • 17
    Will it handle when the app will be updated to the next version on the google play store? – Shajeel Afzal Jun 29 '14 at 13:28
  • 4
    SharedPreferences are maintained during upgrade. So, I assume that when its being upgraded from PlayStore, old value is available. In fact it is applicable for other methods i.e. checking existence of file too. So, shortcut method in that case is to use different preference/file name or value. – Tejasvi Hegde Nov 20 '14 at 10:28
  • @ShajeelAfzal some thing like this may help you public void CheckAndInitAppFirstTime() { final String PREFS_NAME = "TheAppVer"; final String CHECK_VERSION = "1"; //Required ver... final String KEY_NAME = "CheckVersion"; SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); if (!settings.getString(KEY_NAME, "0").equals(CHECK_VERSION)) { //the app is being launched for first time, do something or CHECK_VERSION is different //... settings.edit().putString(KEY_NAME, CHECK_VERSION).commit(); } } – Tejasvi Hegde Nov 20 '14 at 10:42
  • @aman verma: as per the getBoolean description at https://developer.android.com/reference/android/content/SharedPreferences.htmlThe 2nd parameter of getBoolean is the default value if the first parameter doesn't exit, so if "my_first_time" hasn't been set the expression defaults to true. – user2798692 Aug 08 '19 at 15:33
  • There is one issue with using SharedPreferences. If you have a backup rule to restore SharedPreferences and the users reinstalls your app at some point. – Kris B Nov 04 '22 at 02:32
66

I suggest to not only store a boolean flag, but the complete version code. This way you can also query at the beginning if it is the first start in a new version. You can use this information to display a "Whats new" dialog, for example.

The following code should work from any android class that "is a context" (activities, services, ...). If you prefer to have it in a separate (POJO) class, you could consider using a "static context", as described here for example.

/**
 * Distinguishes different kinds of app starts: <li>
 * <ul>
 * First start ever ({@link #FIRST_TIME})
 * </ul>
 * <ul>
 * First start in this version ({@link #FIRST_TIME_VERSION})
 * </ul>
 * <ul>
 * Normal app start ({@link #NORMAL})
 * </ul>
 * 
 * @author schnatterer
 * 
 */
public enum AppStart {
    FIRST_TIME, FIRST_TIME_VERSION, NORMAL;
}

/**
 * The app version code (not the version name!) that was used on the last
 * start of the app.
 */
private static final String LAST_APP_VERSION = "last_app_version";

/**
 * Finds out started for the first time (ever or in the current version).<br/>
 * <br/>
 * Note: This method is <b>not idempotent</b> only the first call will
 * determine the proper result. Any subsequent calls will only return
 * {@link AppStart#NORMAL} until the app is started again. So you might want
 * to consider caching the result!
 * 
 * @return the type of app start
 */
public AppStart checkAppStart() {
    PackageInfo pInfo;
    SharedPreferences sharedPreferences = PreferenceManager
            .getDefaultSharedPreferences(this);
    AppStart appStart = AppStart.NORMAL;
    try {
        pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        int lastVersionCode = sharedPreferences
                .getInt(LAST_APP_VERSION, -1);
        int currentVersionCode = pInfo.versionCode;
        appStart = checkAppStart(currentVersionCode, lastVersionCode);
        // Update version in preferences
        sharedPreferences.edit()
                .putInt(LAST_APP_VERSION, currentVersionCode).commit();
    } catch (NameNotFoundException e) {
        Log.w(Constants.LOG,
                "Unable to determine current app version from pacakge manager. Defenisvely assuming normal app start.");
    }
    return appStart;
}

public AppStart checkAppStart(int currentVersionCode, int lastVersionCode) {
    if (lastVersionCode == -1) {
        return AppStart.FIRST_TIME;
    } else if (lastVersionCode < currentVersionCode) {
        return AppStart.FIRST_TIME_VERSION;
    } else if (lastVersionCode > currentVersionCode) {
        Log.w(Constants.LOG, "Current version code (" + currentVersionCode
                + ") is less then the one recognized on last startup ("
                + lastVersionCode
                + "). Defenisvely assuming normal app start.");
        return AppStart.NORMAL;
    } else {
        return AppStart.NORMAL;
    }
}

It could be used from an activity like this:

public class MainActivity extends Activity {        
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        switch (checkAppStart()) {
        case NORMAL:
            // We don't want to get on the user's nerves
            break;
        case FIRST_TIME_VERSION:
            // TODO show what's new
            break;
        case FIRST_TIME:
            // TODO show a tutorial
            break;
        default:
            break;
        }

        // ...
    }
    // ...
}

The basic logic can be verified using this JUnit test:

public void testCheckAppStart() {
    // First start
    int oldVersion = -1;
    int newVersion = 1;
    assertEquals("Unexpected result", AppStart.FIRST_TIME,
            service.checkAppStart(newVersion, oldVersion));

    // First start this version
    oldVersion = 1;
    newVersion = 2;
    assertEquals("Unexpected result", AppStart.FIRST_TIME_VERSION,
            service.checkAppStart(newVersion, oldVersion));

    // Normal start
    oldVersion = 2;
    newVersion = 2;
    assertEquals("Unexpected result", AppStart.NORMAL,
            service.checkAppStart(newVersion, oldVersion));
}

With a bit more effort you could probably test the android related stuff (PackageManager and SharedPreferences) as well. Anyone interested in writing the test? :)

Note that the above code will only work properly if you don't mess around with your android:versionCode in AndroidManifest.xml!

Community
  • 1
  • 1
schnatterer
  • 7,525
  • 7
  • 61
  • 80
  • 2
    Please explain how to use this method. Where you are initializing the SharedPreferences object? – Shajeel Afzal Jun 29 '14 at 13:49
  • I extended the answer a bit. The easiest way to use it is to just paste the code snippet into an activity and call `checkAppStart()` – schnatterer Jun 30 '14 at 12:37
  • 1
    doesn't work for me - it always launch my first time tutorial – pzo Jul 07 '14 at 08:03
  • "doesn't work" is not really a detailed error description. Anyway, I added a more comprehensive example to the answer. It definitely works for me! – schnatterer Jul 13 '14 at 00:47
  • 1
    this code is alot more straight forward without the side effects of declaring the context and preferences elsewhere `public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)` is a much better method signature – Will Dec 10 '14 at 23:05
  • 2
    Made an update gist of this answer here https://gist.github.com/williscool/2a57bcd47a206e980eee I had an issue with the orginal code where it would get stuck in my walkthrough loop forever because the version number was never being recalculated in the first `checkAppStart` block. so I decided to share my updated code and see if anyone has suggestions about it – Will Dec 11 '14 at 01:47
  • 1
    @Will thanks for your input. You're right, the code could be simplified and made more robust. When I first posted the answer, I extracted the code from [a more complex scenario](https://github.com/schnatterer/nusic/blob/648bd11b55719390b4c73f7eb0c9eb49ffca5e6f/Nusic/src/info/schnatterer/nusic/service/impl/PreferencesServiceSharedPreferences.java#L242), where I wanted to access `AppStart` from different activities. So I put the logic in a separate service method. That's why there was a `context` variable and `AppStart` was stored within a static variable to facilitate idempotent method calls. – schnatterer Dec 11 '14 at 17:00
  • 1
    @Will please see my edit, I hope I hope I've taken all ideas from your gist into account. Note that the method is now no longer idempotent, which should solve your and @user657429's problem, where the version code was never being recalculated. This is a tradeoff, though: if you call the method twice, it will only return `FIRST_TIME_VERSION`/`FIRST_TIME` on the first call of the method. Any subsequent calls will only return `NORMAL`until the app is started again. – schnatterer Dec 11 '14 at 17:02
60

Another idea is to use a setting in the Shared Preferences. Same general idea as checking for an empty file, but then you don't have an empty file floating around, not being used to store anything

Kevin Dion
  • 4,027
  • 1
  • 17
  • 13
  • 4
    beware that this kind of approach could not work on a Samsung Galaxy S with Android Froyo. That's because of a bug in SharedPreferences saving. Here's a link to a SO question on that: http://stackoverflow.com/questions/7296163/cant-save-my-preferences-after-app-killed and here's the ticket on google code: http://code.google.com/p/android/issues/detail?id=14359 – Francesco Rigoni Mar 09 '12 at 08:07
  • 4
    Beware for Android 6.0 (API 23 - Marshmallow) or above auto backup (https://developer.android.com/guide/topics/data/autobackup.html)is enabled by default. If the users uninstalls and then reinstalls the app the shared preferences will be recovered. So on reinstalls you cannot check if it is running for the first time after the reinstall if this is of any concern. – Alan Mar 09 '17 at 23:38
  • 1
    @Alan you are right, this answer is **no longer valid** from Android Marshmallow. – Ioane Sharvadze May 12 '17 at 17:03
  • 1
    @Alan you cannot imagine how long I was looking for an answer like yours. You made my day. Thanks! – Antonio Jun 17 '17 at 23:59
  • @Alan But auto backup also saves most other data. So the reinstalled app is probably expected to be in a non-first-run state. And the user already has used the app before, so there is no need for guidance. So I would argue for most cases it is a good thing this happens. – smdufb Nov 08 '19 at 07:08
  • @Alan do you know of any workaround technique for this? My particular use-case is the one you described; I want to know when the app has been reinstalled. – Uche Ozoemena Sep 06 '21 at 13:08
  • @UcheOzoemena Try excluding the shared preference or disable back up?: https://developer.android.com/guide/topics/data/autobackup.html#IncludingFiles – Alan Sep 07 '21 at 22:14
  • @Alan sadly that breaks another part of my app's functionality so it's not a viable solution for me. – Uche Ozoemena Sep 14 '21 at 12:22
5

I solved to determine whether the application is your first time or not , depending on whether it is an update.

private int appGetFirstTimeRun() {
    //Check if App Start First Time
    SharedPreferences appPreferences = getSharedPreferences("MyAPP", 0);
    int appCurrentBuildVersion = BuildConfig.VERSION_CODE;
    int appLastBuildVersion = appPreferences.getInt("app_first_time", 0);

    //Log.d("appPreferences", "app_first_time = " + appLastBuildVersion);

    if (appLastBuildVersion == appCurrentBuildVersion ) {
        return 1; //ya has iniciado la appp alguna vez

    } else {
        appPreferences.edit().putInt("app_first_time",
                appCurrentBuildVersion).apply();
        if (appLastBuildVersion == 0) {
            return 0; //es la primera vez
        } else {
            return 2; //es una versión nueva
        }
    }
}

Compute results:

  • 0: If this is the first time.
  • 1: It has started ever.
  • 2: It has started once, but not that version , ie it is an update.
Codelaby
  • 2,604
  • 1
  • 25
  • 25
3

There is support for just this in the support library revision 23.3.0 (in the v4 which means compability back to Android 1.6).

In your Launcher activity, first call:

AppLaunchChecker.onActivityCreate(activity);

Then call:

AppLaunchChecker.hasStartedFromLauncher(activity);

Which will return if this was the first time the app was launched.

Lucas Arrefelt
  • 3,879
  • 5
  • 41
  • 71
  • The order of these calls has to be reversed, once AppLaunchChecker.onActivityCreate() has been called, AppLaunchChecker.hasStartedFromLauncher() will be returning true. – Gary Kipnis May 01 '17 at 17:20
  • 2
    This is quite misleading. It doesn't say whether the app is "ever launched"; it, rather, says whether the app "ever launched by a user from launcher". So, there is a possibility that other apps or deep-links may have already launched the app. – Farid Nov 15 '19 at 13:16
3

You can use Android SharedPreferences .

Android SharedPreferences allows us to store private primitive application data in the form of key-value pair .

CODE

Create a custom class SharedPreference

 public class SharedPreference {

    android.content.SharedPreferences pref;
    android.content.SharedPreferences.Editor editor;
    Context _context;
    private static final String PREF_NAME = "testing";

    // All Shared Preferences Keys Declare as #public
    public static final String KEY_SET_APP_RUN_FIRST_TIME       =        "KEY_SET_APP_RUN_FIRST_TIME";


    public SharedPreference(Context context) // Constructor
    {
        this._context = context;
        pref = _context.getSharedPreferences(PREF_NAME, 0);
        editor = pref.edit();

    }

    /*
    *  Set Method Generally Store Data;
    *  Get Method Generally Retrieve Data ;
    * */


    public void setApp_runFirst(String App_runFirst)
    {
        editor.remove(KEY_SET_APP_RUN_FIRST_TIME);
        editor.putString(KEY_SET_APP_RUN_FIRST_TIME, App_runFirst);
        editor.apply();
    }

    public String getApp_runFirst()
    {
        String  App_runFirst= pref.getString(KEY_SET_APP_RUN_FIRST_TIME, "FIRST");
        return  App_runFirst;
    }

}

Now Open Your Activity & Initialize .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Now Call this in OnCreate section

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Now Checking

if(sharedPreferenceObj.getApp_runFirst().equals("FIRST"))
 {
   // That's mean First Time Launch
   // After your Work , SET Status NO
   sharedPreferenceObj.setApp_runFirst("NO");
 }
else
 { 
   // App is not First Time Launch
 }
Vaibhav
  • 136
  • 1
  • 3
  • 13
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
3

Here's some code for this -

String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/Android/data/myapp/files/myfile.txt";

boolean exists = (new File(path)).exists(); 

if (!exists) {
    doSomething();                                      
}
else {
    doSomethingElse();
}
woz
  • 10,888
  • 3
  • 34
  • 64
Arunabh Das
  • 13,212
  • 21
  • 86
  • 109
2

You could simply check for the existence of an empty file, if it doesn't exist, then execute your code and create the file.

e.g.

if(File.Exists("emptyfile"){
    //Your code here
    File.Create("emptyfile");
}
MechMK1
  • 3,278
  • 7
  • 37
  • 55
  • I was thinking of doing that but thought there must be a better way – Boardy Jan 08 '11 at 21:10
  • I don't know any, but what is the lack of ressources you recieve by that? 4 bytes for the file and one "if" at the beginning. System-routines would do the same, they'd do exactly the same or make a table with applications which have already been lauched – MechMK1 Jan 08 '11 at 21:13
  • In a similar fashion you can use sharedpreferences, which if it doesn't exist, you show a splash screen etc... and just create it when program is first run (obv after checking for it). See Kevin's answer above – stealthcopter Jan 08 '11 at 21:30
2

If you are looking for a simple way, here it is.

Create a utility class like this,

public class ApplicationUtils {

  /**
  * Sets the boolean preference value
  *
  * @param context the current context
  * @param key     the preference key
  * @param value   the value to be set
  */
 public static void setBooleanPreferenceValue(Context context, String key, boolean value) {
     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
     sp.edit().putBoolean(key, value).apply();
 }

 /**
  * Get the boolean preference value from the SharedPreference
  *
  * @param context the current context
  * @param key     the preference key
  * @return the the preference value
  */
 public static boolean getBooleanPreferenceValue(Context context, String key) {
     SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
     return sp.getBoolean(key, false);
 }

}

At your Main Activity, onCreate()

if(!ApplicationUtils.getBooleanPreferenceValue(this,"isFirstTimeExecution")){
Log.d(TAG, "First time Execution");
ApplicationUtils.setBooleanPreferenceValue(this,"isFirstTimeExecution",true);
// do your first time execution stuff here,
}
Vaibhav
  • 136
  • 1
  • 3
  • 13
Hardian
  • 1,922
  • 22
  • 23
1

I made a simple class to check if your code is running for the first time/ n-times!

Example

Create a unique preferences

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Use runTheFirstTime, choose a key to check your event

if (prefFirstTime.runTheFirstTime("myKey")) {
    Toast.makeText(this, "Test myKey & coutdown: " + prefFirstTime.getCountDown("myKey"),
                   Toast.LENGTH_LONG).show();
}

Use runTheFirstNTimes, choose a key and how many times execute

if(prefFirstTime.runTheFirstNTimes("anotherKey" , 5)) {
    Toast.makeText(this, "ciccia Test coutdown: "+ prefFirstTime.getCountDown("anotherKey"),
                   Toast.LENGTH_LONG).show();
}
  • Use getCountDown() to better handle your code

FirstTimePreference.java

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
1

for kotlin

    fun checkFirstRun() {

    var prefs_name = "MyPrefsFile"
    var pref_version_code_key = "version_code"
    var doesnt_exist: Int = -1;

    // Get current version code
    var currentVersionCode = BuildConfig.VERSION_CODE

    // Get saved version code
    var prefs: SharedPreferences = getSharedPreferences(prefs_name, MODE_PRIVATE)
    var savedVersionCode: Int = prefs.getInt(pref_version_code_key, doesnt_exist)

    // Check for first run or upgrade
    if (currentVersionCode == savedVersionCode) {

        // This is just a normal run
        return;

    } else if (savedVersionCode == doesnt_exist) {

        // TODO This is a new install (or the user cleared the shared preferences)


    } else if (currentVersionCode > savedVersionCode) {

        // TODO This is an upgrade
    }

    // Update the shared preferences with the current version code
    prefs.edit().putInt(pref_version_code_key, currentVersionCode).apply();

}
K.Hayoev
  • 404
  • 1
  • 4
  • 14
0

Why not use the Database Helper ? This will have a nice onCreate which is only called the first time the app is started. This will help those people who want to track this after there initial app has been installed without tracking.

slott
  • 3,266
  • 1
  • 35
  • 30
  • Does that create a database? How to use the DatabaseHelper without creating an actual database? And I think, `onCreate()` is called for every new version. Also, wouldn't it be considered superfluous or using something for an unintended purpose? – ADTC Aug 16 '14 at 06:31
  • onCreate is only triggered when the app is installed the first time. When the db version is incremented the onUpdated is triggered. – slott Aug 16 '14 at 08:23
  • Well superfluous is such a harsh word :) - If you have the option ie. your app is not yet live yet then setup a SharedPrefs flag and use that to determine is it's first boot or not. I had a case where the app had been in the wild for some time and we were using a DB so the onCreate was a perfect match for me. – slott Aug 18 '14 at 07:40
0

I like to have an "update count" in my shared preferences. If it's not there (or default zero value) then this is my app's "first use".

private static final int UPDATE_COUNT = 1;    // Increment this on major change
...
if (sp.getInt("updateCount", 0) == 0) {
    // first use
} else if (sp.getInt("updateCount", 0) < UPDATE_COUNT) {
    // Pop up dialog telling user about new features
}
...
sp.edit().putInt("updateCount", UPDATE_COUNT);

So now, whenever there's an update to the app that users should know about, I increment UPDATE_COUNT

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
0

My version for kotlin looks like the following:

PreferenceManager.getDefaultSharedPreferences(this).apply {
        // Check if we need to display our OnboardingSupportFragment
        if (!getBoolean("wasAppStartedPreviously", false)) {
            // The user hasn't seen the OnboardingSupportFragment yet, so show it
            startActivity(Intent(this@SplashScreenActivity, AppIntroActivity::class.java))
        } else {
            startActivity(Intent(this@SplashScreenActivity, MainActivity::class.java))
        }
    }
romaneso
  • 1,097
  • 1
  • 10
  • 26
0

An improved version of K.Hayoev but boolean one

 fun isFirstRun(): Boolean {

    var prefs_name = "MyPrefsFile"
    var pref_version_code_key = "version_code"
    var doesnt_exist: Int = -1;

    // Get current version code
    var currentVersionCode = BuildConfig.VERSION_CODE

    // Get saved version code
    var prefs: SharedPreferences = requireContext().getSharedPreferences(prefs_name, MODE_PRIVATE)
    var savedVersionCode: Int = prefs.getInt(pref_version_code_key, doesnt_exist)

    // Check for first run or upgrade
    if (currentVersionCode == savedVersionCode) {

        // This is just a normal run
        return false;

    } else if (savedVersionCode <= doesnt_exist) {
        prefs.edit().putInt(pref_version_code_key, currentVersionCode).apply();
        return true
        // TODO This is a new install (or the user cleared the shared preferences)

    } else if (currentVersionCode > savedVersionCode) {
        return false;
        // TODO This is an upgrade
    }
    prefs.edit().putInt(pref_version_code_key, currentVersionCode).apply();
    return false
    // Update the shared preferences with the current version code

}
Maher
  • 342
  • 3
  • 10
-2

Hi guys I am doing something like this. And its works for me

create a Boolean field in shared preference.Default value is true {isFirstTime:true} after first time set it to false. Nothing can be simple and relaiable than this in android system.

DropAndTrap
  • 1,538
  • 16
  • 24
  • Uh, don't hardcode the path like that! If you simply do `Context.getSharedPreferences()` it will end up in the same place, except it will work everywhere – Takhion Jul 07 '15 at 16:13