Визначте, чи використовується програма Android вперше


112

Зараз я розробляю додаток для android. Мені потрібно щось робити, коли додаток запускається вперше, тобто код запускається лише при першому запуску програми.


1
Коли я вперше почав робити додатки, я думав лише про перший запуск після встановлення програми. Пізніше я зрозумів, що мені також потрібно обробляти та диференціювати перші прогони після оновлення. Відповідь @ schnatterer нижче, і моя відповідь тут показує, як це зробити. Будьте обережні до відповідей, які не враховують оновлення.
Сурагч

@Suragch ти поводишся так, як це погана практика не брати до уваги оновлення, але в деяких випадках, наприклад, запровадження програми, ти НЕ хочеш цього робити :)
creativecreatorormaybenot

@creativecreatorormaybenot, це правда. Бувають випадки, коли ви дбаєте лише про початкову установку, а не про наступні оновлення. Простих булів достатньо для цих ситуацій. Однак що робити, якщо через деякий час ви хочете додати інше вступ для поточних користувачів про всі нові функції, які ви щойно додали в останньому оновлення? На мій погляд, більш далекоглядно перевірити номер версії, а не булева. Це, принаймні, дає вам можливість у майбутньому відповісти одним із способів нової установки та іншим способом оновлення.
Сурагч

1
Тоді ви просто додаєте його до цієї версії, але я отримую йоз
creativecreatorormaybenot

Ви можете перевірити це stackoverflow.com/a/7217834/2689076
Vaibhav

Відповіді:


56

Інша ідея полягає у використанні налаштувань у спільних налаштуваннях. Та сама загальна ідея, як перевірка порожнього файлу, але тоді у вас немає плаваючого порожнього файлу, який не використовується для зберігання нічого


3
майте на увазі, що подібний підхід не міг працювати на Samsung Galaxy S з Android Froyo. Це через помилку в економії SharedPreferences. Ось посилання на запитання щодо цього питання: stackoverflow.com/questions/7296163/…, і ось квиток на код google: code.google.com/p/android/isissue/detail?id=14359
Франческо Рігоні,

4
Остерігайтеся для Android 6.0 (API 23 - Marshmallow) або вище автоматичного резервного копіювання ( developer.android.com/guide/topics/data/autobackup.html)включено за замовчуванням. Якщо користувачі видаляють і потім перевстановлять додаток, спільні налаштування будуть відновлені. Тож при перевстановці ви не можете перевірити, чи працює вона вперше після перевстановлення, якщо це викликає занепокоєння.
Алан

1
@Алан, ви праві, ця відповідь більше не є дійсною від Android Marshmallow.
Іоан Шарвадзе

1
@Алан, ти не уявляєш, як довго я шукав відповіді, як ти. Ти зробив мій день. Дякую!
Антоніо

@Alan Але автоматичне резервне копіювання також зберігає більшість інших даних. Тож, напевно, очікується, що перевстановлений додаток перебуває у не запущеному стані. І користувач уже використовував додаток раніше, тому немає необхідності в керівництві. Тому я б заперечував у більшості випадків, що це добре.
smdufb

112

Ви можете використовувати SharedPreferences, щоб визначити, чи це програма "Перший раз". Просто використовуйте булеву змінну ("my_first_time") і змініть її значення на помилкове, коли ваше завдання для "першого разу" закінчиться.

Це мій код, коли ви вперше відкриваєте додаток:

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
Чи впорається він, коли додаток буде оновлено до наступної версії в магазині Google Play?
Shajeel Afzal

4
SharedPreferences зберігаються під час оновлення. Отже, я припускаю, що при його оновленні від PlayStore старе значення стає доступним. Насправді це застосовно і для інших методів, тобто перевірки наявності файлу. Отже, метод ярлика в цьому випадку полягає у використанні різних переваг / імені файлу чи значення.
Tejasvi Hegde

@ShajeelAfzal щось подібне може допомогти вам відкрити недійсні CheckAndInitAppFirstTime () {final String PREFS_NAME = "TheAppVer"; заключний рядок CHECK_VERSION = "1"; // Обов’язковий ver ... final String KEY_NAME = "CheckVersion"; Налаштування спільних параметрів = getSharedPreferences (PREFS_NAME, 0); якщо (! settings.getString (KEY_NAME, "0"). дорівнює (CHECK_VERSION)) {// програма запускається вперше, зробіть щось або CHECK_VERSION відрізняється // ... settings.edit (). putString ( KEY_NAME, CHECK_VERSION) .комітувати (); }}
Техасві Хегде

@aman verma: відповідно до опису getBoolean на developer.android.com/reference/android/content/… 2-й параметр getBoolean - це значення за замовчуванням, якщо перший параметр не виходить, тому якщо "my_first_time" не встановлено вираз за замовчуванням до істинного.
користувач2798692

62

Я пропоную зберігати не лише булівський прапор, а й повний код версії. Таким чином, ви також можете запитати на початку, якщо це перший старт у новій версії. Ви можете використовувати цю інформацію для відображення, наприклад, діалогового вікна "Що нового".

Наступний код повинен працювати з будь-якого класу Android, який "є контекстом" (діяльність, послуги, ...). Якщо ви хочете мати його в окремому (POJO) класі, ви можете розглянути можливість використання "статичного контексту", як описано тут, наприклад.

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

Він може бути використаний у такій діяльності:

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

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

Основну логіку можна перевірити за допомогою цього тесту 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));
}

Трохи доклавши більше зусиль, ви, можливо, також зможете протестувати пов'язані з Android речі (PackageManager та SharedPreferences). Хтось зацікавлений у написанні тесту? :)

Зауважте, що вищевказаний код буде працювати належним чином лише у тому випадку, якщо ви не заплутаєтесь із своїм android:versionCodeв AndroidManifest.xml!


2
Поясніть, будь ласка, як використовувати цей метод. Де ви ініціалізуєте об’єкт SharedPreferences?
Shajeel Afzal

1
не працює для мене - він завжди запускає свій перший підручник
пзо

1
цей код набагато більше прямо вперед без побічних ефектів оголосити контекст і переваги в інших місцях public AppStart checkAppStart(Context context, SharedPreferences sharedPreferences)набагато кращий метод підпису
Will

2
Тут було зроблено суть оновлення цієї відповіді gist.github.com/williscool/2a57bcd47a206e980eee У мене виникла проблема з початковим кодом, який назавжди застряг у моєму циклі проходження, оскільки номер версії ніколи не перераховувався в першому checkAppStartблоці. так що я вирішив поділитися своїм оновлений код і подивитися , якщо у кого є пропозиції по цього приводу
Волю

1
@ Дякую за ваш внесок. Ви маєте рацію, код можна спростити і зробити більш надійним. Коли я вперше опублікував відповідь, я витягнув код із складнішого сценарію , де я хотів отримати доступ AppStartдо різних видів діяльності. Тому я вклав логіку в окремий метод обслуговування. Ось чому існувала contextзмінна і AppStartзберігалася в статичній змінній для полегшення ідентифікаційних викликів методу.
шнайтер

4

Я вирішив визначити, додаток у вас вперше чи ні, залежно від того, чи це оновлення.

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

Обчислити результати:

  • 0: Якщо це вперше.
  • 1: Це почалося коли-небудь.
  • 2: Він розпочався один раз, але не та версія, тобто оновлення.

3

Ви можете використовувати Android SharedPreferences .

Android SharedPreferences дозволяє зберігати дані приватних примітивних програм у вигляді пари ключ-значення.

КОД

Створіть користувацький клас 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;
    }

}

Тепер відкрийте свою діяльність та ініціалізуйте .

 private     SharedPreference                sharedPreferenceObj; // Declare Global

Тепер зателефонуйте цьому в розділ OnCreate

 sharedPreferenceObj=new SharedPreference(YourActivity.this);

Тепер перевірка

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

Ось код для цього -

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

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

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

1

Ви можете просто перевірити наявність порожнього файлу, якщо його немає, а потім виконати свій код і створити файл.

напр

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

Я думав зробити це, але подумав, що повинен бути кращий шлях
Boardy

Я не знаю жодного, але яка брак ресурсів ви отримуєте за це? 4 байти для файлу і один "якщо" на початку. Підпрограми системи зробили б те саме, вони зробили б точно так само або склали таблицю з уже запущеними програмами
MechMK1

Аналогічно ви можете використовувати спільні налаштування, які, якщо їх не існує, ви показуєте екран сплеску тощо ... і просто створюєте його під час першого запуску програми (obv після перевірки на неї). Дивіться відповідь Кевіна вище
stealthcopter

1

Я створив простий клас, щоб перевірити, чи працює ваш код вперше / n-раз!

Приклад

Створіть унікальні налаштування

FirstTimePreference prefFirstTime = new FirstTimePreference(getApplicationContext());

Використовуйте runTheFirstTime, виберіть ключ, щоб перевірити свою подію

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

Використовуйте runTheFirstNTimes, виберіть ключ і скільки разів виконуйте

if(prefFirstTime.runTheFirstNTimes("anotherKey" , 5)) {
    Toast.makeText(this, "ciccia Test coutdown: "+ prefFirstTime.getCountDown("anotherKey"),
                   Toast.LENGTH_LONG).show();
}
  • Використовуйте getCountDown () для кращого керування кодом

FirstTimePreference.java


1

Підтримка саме цього є у версії бібліотеки підтримки 23.3.0 (у версії 4, що означає сумісність з Android 1.6).

У своєму запуску, перший дзвінок:

AppLaunchChecker.onActivityCreate(activity);

Потім зателефонуйте:

AppLaunchChecker.hasStartedFromLauncher(activity);

Що повернеться, якщо це було вперше запуск програми.


Після виклику AppLaunchChecker.onActivityCreate () буде вимкнено порядок цих викликів, AppLaunchChecker.hasStartedFromLauncher () повернеться істинним.
Гері Кіпніс

Це досить оману. Він не говорить про те, чи додаток "коли-небудь запущене"; він, скоріше, говорить, чи додаток "коли-небудь запускається користувачем із запуску". Таким чином, існує ймовірність, що інші програми або прямі посилання, можливо, вже запустили додаток.
Фарид

1

Якщо ви шукаєте простий спосіб, ось він.

Створіть такий клас корисності,

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

}

У вашій основній діяльності, 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

для котлін

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

}

Дуже дякую за відповідь у Котліні
MMG

0

Чому б не використовувати помічник бази даних? Це буде приємно onCreate, яке називається тільки при першому запуску програми. Це допоможе тим людям, які хочуть відстежувати це після встановлення початкового додатку без відстеження.


Це створює базу даних? Як користуватися DatabaseHelper без створення фактичної бази даних? І я думаю, onCreate()називається для кожної нової версії. Крім того, чи не вважатиметься це зайвим чи використовувати щось із непередбачуваною метою?
ADTC

onCreate запускається лише тоді, коли додаток встановлено вперше. При збільшенні версії db спрацьовує onUpdated.
слот

Ну зайвим є таке суворе слово :) - Якщо у вас є варіант, тобто. ваш додаток ще не працює, тоді встановіть прапор SharedPrefs і використовуйте це, щоб визначити, це перший завантаження чи ні. У мене був випадок, коли додаток деякий час був у дикій природі, і ми використовували БД, тому onCreate був ідеальним для мене.
слот

0

Мені подобається мати "кількість оновлень" у своїх спільних налаштуваннях. Якщо його немає (або нульове значення за замовчуванням), це "перше використання" мого додатка.

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

Тому тепер, коли є оновлення програми, про яке повинні знати користувачі, я збільшую 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

Привіт, хлопці, я роблю щось подібне. І це працює для мене

створіть булеве поле у ​​спільній перевазі. Значення за замовчуванням - це істина {isFirstTime: true} після першого разу встановіть його на значення false. Ніщо не може бути простим і надійним, ніж це в системі Android.


Ні, не жорстко кодуйте такий шлях! Якщо ви просто зробите Context.getSharedPreferences()це, він опиниться там же, за винятком того, що він буде працювати скрізь
Takhion

погоджуюся з вами :)
DropAndTrap
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.