Determina se l'app Android viene utilizzata per la prima volta


112

Attualmente sto sviluppando un'app per Android. Devo fare qualcosa quando l'app viene avviata per la prima volta, ovvero il codice viene eseguito solo la prima volta che viene avviato il programma.


1
Quando ho iniziato a creare app, pensavo solo alla prima esecuzione dopo l'installazione di un'app. In seguito ho capito che dovevo anche gestire e differenziare le prime esecuzioni dopo gli aggiornamenti. La risposta di @ schnatterer qui sotto e la mia risposta qui mostrano come farlo. Fai attenzione alle risposte che non tengono conto degli aggiornamenti.
Suragch

@ Suragch ti comporti come se fosse una cattiva pratica non prendere in considerazione gli aggiornamenti, ma in alcuni casi, come avere un'introduzione all'app, NON vuoi farlo :)
creativecreatorormaybenot

@creativecreatorormaybenot, è vero. Ci sono momenti in cui ti interessa solo l'installazione iniziale e non gli aggiornamenti successivi. Un semplice booleano è sufficiente per queste situazioni. Tuttavia, cosa succederebbe se in futuro volessi aggiungere un'introduzione diversa per gli attuali utenti su tutte le nuove funzionalità che hai appena aggiunto nell'ultimo aggiornamento? A mio parere è più lungimirante controllare il numero di versione piuttosto che un booleano. Questo almeno ti dà la possibilità in futuro di rispondere in un modo per una nuova installazione e in un altro modo per un aggiornamento.
Suragch

1
Quindi lo aggiungi solo per questa versione ma ottengo yoz
creativecreatorormaybenot

Risposte:


56

Un'altra idea è usare un'impostazione nelle Preferenze condivise. Stessa idea generale della ricerca di un file vuoto, ma in questo caso non hai un file vuoto che fluttua, non utilizzato per memorizzare nulla


3
attenzione che questo tipo di approccio non potrebbe funzionare su un Samsung Galaxy S con Android Froyo. Ciò è dovuto a un bug nel salvataggio di SharedPreferences. Ecco un link a una domanda SO su questo: stackoverflow.com/questions/7296163/… ed ecco il ticket su google code: code.google.com/p/android/issues/detail?id=14359
Francesco Rigoni

4
Attenzione per Android 6.0 (API 23 - Marshmallow) o versioni successive il backup automatico ( developer.android.com/guide/topics/data/autobackup.html) è abilitato per impostazione predefinita. Se gli utenti disinstalla e poi reinstalla l'app, le preferenze condivise verranno ripristinate. Quindi durante le reinstallazioni non è possibile verificare se è in esecuzione per la prima volta dopo la reinstallazione se questo è motivo di preoccupazione.
Alan

1
@Alan hai ragione, questa risposta non è più valida da Android Marshmallow.
Ioane Sharvadze

1
@Alan non puoi immaginare quanto tempo stavo cercando una risposta come la tua. Hai reso la mia giornata. Grazie!
Antonio

@Alan Ma il backup automatico salva anche la maggior parte degli altri dati. Quindi è probabile che l'app reinstallata si trovi in ​​uno stato non di prima esecuzione. E l'utente ha già utilizzato l'app in precedenza, quindi non è necessaria alcuna guida. Quindi direi che per la maggior parte dei casi è una buona cosa che questo accada.
smdufb

112

È possibile utilizzare SharedPreferences per identificare se è la "prima volta" che l'app viene avviata. Usa semplicemente una variabile booleana ("my_first_time") e cambia il suo valore in false quando la tua attività per la "prima volta" è terminata.

Questo è il mio codice per catturare la prima volta che apri l'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(); 
}

17
Gestirà quando l'app verrà aggiornata alla prossima versione su Google Play Store?
Shajeel Afzal

4
Le preferenze condivise vengono mantenute durante l'aggiornamento. Quindi, presumo che quando viene aggiornato da PlayStore, il vecchio valore sia disponibile. In effetti è applicabile anche ad altri metodi, ad esempio il controllo dell'esistenza del file. Quindi, il metodo di scelta rapida in questo caso consiste nell'usare una preferenza / nome file o valore diverso.
Tejasvi Hegde

@ShajeelAfzal qualcosa del genere potrebbe aiutarti a pubblicizzare void CheckAndInitAppFirstTime () {final String PREFS_NAME = "TheAppVer"; stringa finale CHECK_VERSION = "1"; // Ver richiesta ... final String KEY_NAME = "CheckVersion"; Impostazioni SharedPreferences = getSharedPreferences (PREFS_NAME, 0); if (! settings.getString (KEY_NAME, "0"). equals (CHECK_VERSION)) {// l'app viene avviata per la prima volta, fai qualcosa o CHECK_VERSION è diverso // ... settings.edit (). putString ( KEY_NAME, CHECK_VERSION) .commit (); }}
Tejasvi Hegde

@aman verma: come da descrizione getBoolean su developer.android.com/reference/android/content/… Il secondo parametro di getBoolean è il valore predefinito se il primo parametro non esce, quindi se "my_first_time" non è stato impostato il valore predefinito dell'espressione è true.
user2798692

63

Suggerisco di memorizzare non solo un flag booleano, ma il codice completo della versione. In questo modo puoi anche interrogare all'inizio se è il primo avvio in una nuova versione. È possibile utilizzare queste informazioni per visualizzare una finestra di dialogo "Novità", ad esempio.

Il codice seguente dovrebbe funzionare da qualsiasi classe Android che "è un contesto" (attività, servizi, ...). Se preferisci averlo in una classe separata (POJO), potresti considerare l'utilizzo di un "contesto statico", come descritto qui per esempio.

/**
 * 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;
    }
}

Potrebbe essere utilizzato da un'attività come questa:

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;
        }

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

La logica di base può essere verificata utilizzando questo test JUnit:

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));
}

Con un po 'più di sforzo potresti probabilmente testare anche le cose relative ad Android (PackageManager e SharedPreferences). Qualcuno interessato a scrivere il test? :)

Nota che il codice sopra funzionerà correttamente solo se non giochi con il tuo android:versionCodein AndroidManifest.xml!


2
Spiega come utilizzare questo metodo. Dove stai inizializzando l'oggetto SharedPreferences?
Shajeel Afzal

1
non funziona per me - lancia sempre il mio primo tutorial
pzo

1
questo codice è molto più semplice senza gli effetti collaterali di dichiarare il contesto e le preferenze altrove public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)è una firma del metodo molto migliore
Will

2
Ho creato un aggiornamento essenziale di questa risposta qui gist.github.com/williscool/2a57bcd47a206e980eee Ho avuto un problema con il codice originale in cui si sarebbe bloccato per sempre nel mio ciclo di guida perché il numero di versione non veniva mai ricalcolato nel primo checkAppStartblocco. così ho deciso di condividere il mio codice aggiornato e vedere se qualcuno ha suggerimenti al riguardo
Will

1
@ Will grazie per il tuo contributo. Hai ragione, il codice potrebbe essere semplificato e reso più robusto. Quando ho pubblicato per la prima volta la risposta, ho estratto il codice da uno scenario più complesso , a cui volevo accedere AppStartda diverse attività. Quindi ho inserito la logica in un metodo di servizio separato. Ecco perché c'era una contextvariabile ed AppStartera memorizzata all'interno di una variabile statica per facilitare le chiamate di metodi idempotenti.
schnatterer

4

Ho risolto per determinare se l'applicazione è la prima volta o meno, a seconda che si tratti di un aggiornamento.

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
        }
    }
}

Risultati di calcolo:

  • 0: se è la prima volta.
  • 1: è iniziato da sempre.
  • 2: È stato avviato una volta, ma non quella versione, ovvero è un aggiornamento.

3

Puoi usare Android SharedPreferences .

Android SharedPreferences ci consente di memorizzare i dati di applicazioni primitive private sotto forma di coppia chiave-valore.

CODICE

Crea una classe personalizzata 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;
    }

}

Ora apri la tua attività e inizializza .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Ora chiamalo nella sezione OnCreate

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Ora controllo

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
 }

2

Ecco del codice per questo -

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

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

if (!exists) {
    doSomething();                                      
}
else {
    doSomethingElse();
}

1

Potresti semplicemente verificare l'esistenza di un file vuoto, se non esiste, quindi eseguire il codice e creare il file.

per esempio

if(File.Exists("emptyfile"){
    //Your code here
    File.Create("emptyfile");
}

Stavo pensando di farlo, ma ho pensato che ci doveva essere un modo migliore
Boardy

Non ne conosco nessuno, ma qual è la mancanza di risorse che ricevi da questo? 4 byte per il file e un "se" all'inizio. Le routine di sistema farebbero lo stesso, farebbero esattamente lo stesso o
creerebbero

In modo simile puoi usare sharedpreferences, che se non esiste, mostri uno splash screen ecc ... e lo crei semplicemente quando il programma viene eseguito per la prima volta (ovviamente dopo averlo controllato). Vedi la risposta di Kevin sopra
Stealthcopter

1

Ho creato una semplice classe per verificare se il tuo codice è in esecuzione per la prima volta / n volte!

Esempio

Crea preferenze uniche

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Usa runTheFirstTime, scegli una chiave per controllare il tuo evento

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

Usa runTheFirstNTimes, scegli una chiave e quante volte esegui

if(prefFirstTime.runTheFirstNTimes("anotherKey" , 5)) {
    Toast.makeText(this, "ciccia Test coutdown: "+ prefFirstTime.getCountDown("anotherKey"),
                   Toast.LENGTH_LONG).show();
}
  • Usa getCountDown () per gestire meglio il tuo codice

FirstTimePreference.java


1

C'è supporto per proprio questo nella revisione della libreria di supporto 23.3.0 (nella v4 che significa compatibilità con Android 1.6).

Nella tua attività Launcher, prima chiama:

AppLaunchChecker.onActivityCreate(activity);

Quindi chiama:

AppLaunchChecker.hasStartedFromLauncher(activity);

Che tornerà se questa è stata la prima volta che l'app è stata avviata.


L'ordine di queste chiamate deve essere invertito, una volta che AppLaunchChecker.onActivityCreate () è stato chiamato, AppLaunchChecker.hasStartedFromLauncher () restituirà true.
Gary Kipnis

Questo è abbastanza fuorviante. Non dice se l'app è "mai stata lanciata"; piuttosto, dice se l'app "è mai stata lanciata da un utente dal programma di avvio". Quindi, esiste la possibilità che altre app o link diretti abbiano già avviato l'app.
Farid

1

Se stai cercando un modo semplice, eccolo qui.

Crea una classe di utilità come questa,

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);
 }

}

Nella tua attività principale, onCreate ()

if(!ApplicationUtils.getBooleanPreferenceValue(this,"isFirstTimeExecution")){
Log.d(TAG, "First time Execution");
ApplicationUtils.setBooleanPreferenceValue(this,"isFirstTimeExecution",true);
// do your first time execution stuff here,
}

1

per 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();

}

Grazie mille per aver risposto a Kotlin
MMG

0

Perché non utilizzare Database Helper? Questo avrà un bel onCreate che viene chiamato solo la prima volta che l'app viene avviata. Ciò aiuterà le persone che desiderano tenerne traccia dopo che l'app iniziale è stata installata senza tracciamento.


Questo crea un database? Come utilizzare DatabaseHelper senza creare un database reale? E penso che onCreate()sia necessaria ogni nuova versione. Inoltre, non sarebbe considerato superfluo o utilizzare qualcosa per uno scopo non intenzionale?
ADTC

onCreate viene attivato solo quando l'app viene installata per la prima volta. Quando la versione del db viene incrementata, viene attivato onUpdated.
Slott

Bene, superfluo è una parola così dura :) - Se hai l'opzione, ad es. la tua app non è ancora attiva, quindi imposta un flag SharedPrefs e usalo per determinare se è il primo avvio o meno. Ho avuto un caso in cui l'app era in circolazione da un po 'di tempo e stavamo usando un DB, quindi onCreate era perfetto per me.
Slott

0

Mi piace avere un "conteggio degli aggiornamenti" nelle mie preferenze condivise. Se non è presente (o il valore predefinito è zero), questo è il "primo utilizzo" della mia app.

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);

Quindi ora, ogni volta che c'è un aggiornamento per l'app di cui gli utenti dovrebbero conoscere, incremento UPDATE_COUNT


-1
    /**
     * @author ALGO
     */
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    import java.util.UUID;

    import android.content.Context;

    public class Util {
        // ===========================================================
        //
        // ===========================================================

        private static final String INSTALLATION = "INSTALLATION";

        public synchronized static boolean isFirstLaunch(Context context) {
            String sID = null;
            boolean launchFlag = false;
            if (sID == null) {
                File installation = new File(context.getFilesDir(), INSTALLATION);
                try {
                    if (!installation.exists()) {

                        writeInstallationFile(installation);
                    }
                    sID = readInstallationFile(installation);
launchFlag = true;
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            return launchFlag;
        }

        private static String readInstallationFile(File installation) throws IOException {
            RandomAccessFile f = new RandomAccessFile(installation, "r");// read only mode
            byte[] bytes = new byte[(int) f.length()];
            f.readFully(bytes);
            f.close();

            return new String(bytes);
        }

        private static void writeInstallationFile(File installation) throws IOException {
            FileOutputStream out = new FileOutputStream(installation);
            String id = UUID.randomUUID().toString();
            out.write(id.getBytes());
            out.close();
        }
    }

> Usage (in class extending android.app.Activity)

Util.isFirstLaunch(this);

-2

Ciao ragazzi, sto facendo qualcosa del genere. E per me funziona

creare un campo booleano nella preferenza condivisa. Il valore predefinito è true {isFirstTime: true} dopo la prima volta impostarlo su false. Niente può essere semplice e affidabile di questo nel sistema Android.


Uh, non codificare il percorso in questo modo! Se lo fai semplicemente Context.getSharedPreferences()finirà nello stesso posto, tranne che funzionerà ovunque
Takhion

d'accordo con te :)
DropAndTrap
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.