Как вызвать функцию только после открытия приложения? [Дубликат]

Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я их добавлю:

Случай с краем # 1: одновременный доступ к Словарю

Родовые словари в .NET не являются потокобезопасными, а иногда могут бросать NullReference или даже (чаще) a KeyNotFoundException при попытке получить доступ к ключу из двух параллельных потоков. Исключение в этом случае является довольно ошибочным.

Случай с краем # 2: небезопасный код

Если код NullReferenceException задан кодом unsafe, вы можете посмотреть на переменные указателя , и проверьте их на IntPtr.Zero или что-то в этом роде. Это одно и то же («исключение нулевого указателя»), но в небезопасном коде переменные часто переводятся в типы значений / массивы и т. Д., И вы ударяете головой о стену, задаваясь вопросом, как тип значения может исключение.

(Еще одна причина для небезопасного использования небезопасного кода, если вам это нужно)

21
задан Michell Bak 9 September 2011 в 12:44
поделиться

9 ответов

SharedPreferences кажется уродливым решением для меня. Это гораздо более удобно, когда вы используете конструктор приложений для таких целей.

Все, что вам нужно, это использовать свой собственный класс приложения, а не по умолчанию.

public class MyApp extends Application {

    public MyApp() {
        // this method fires only once per application start. 
        // getApplicationContext returns null here

        Log.i("main", "Constructor fired");
    }

    @Override
    public void onCreate() {
        super.onCreate();    

        // this method fires once as well as constructor 
        // but also application has context here

        Log.i("main", "onCreate fired"); 
    }
}

Затем вы должны зарегистрировать этот класс как ваш класс приложения в AndroidManifest.xml

<application android:label="@string/app_name" android:name=".MyApp"> <------- here
    <activity android:name="MyActivity"
              android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
</application>

Вы даже можете нажать кнопку «Назад», поэтому приложение перейдет на задний план и не будет тратить ресурсы процессора, только ресурс памяти, а затем вы можете запустить его снова и конструктор все еще не горит, так как приложение еще не закончено.

Вы можете очистить память в диспетчере задач, чтобы все приложения были закрыты, а затем перезапустите приложение, чтобы убедиться, что ваш код инициализации снова запущен.

50
ответ дан Vitalii Korsakov 26 August 2018 в 17:50
поделиться

Я просто решил сделать это сам, я повторно открываю свое основное действие несколько раз во время исполнения приложения. Хотя конструктор является допустимым подходом к некоторым вещам, он не позволяет вам получить доступ к текущему контексту приложения, чтобы писать тосты между прочим.

Мое решение состояло в том, чтобы создать простой булевский набор firstRun для true в классе моего MainActivity, оттуда я запустил содержимое инструкции if, а затем установил его в true. Пример:

public class MainActivity extends AppCompatActivity
{
     private static boolean firstRun = true;

     @Override
     protected void onCreate(Bundle savedInstanceState)
     {
         if(firstRun)
         {
              Toast.makeText(getApplicationContext(), "FIRST RUN", Toast.LENGTH_SHORT).show();
              //YOUR FIRST RUN CODE HERE
         }
         firstRun = false;

         super.onCreate(savedInstanceState);
         //THE REST OF YOUR CODE
}
0
ответ дан Eric Adam Fortney 26 August 2018 в 17:50
поделиться
 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
  if (!prefs.getBoolean("onlyonce", false)) {
    // <---- run your one time code here


    // mark once runned.
    SharedPreferences.Editor editor = prefs.edit();
    editor.putBoolean("onlyonce", true);
    editor.commit();
  }
}
0
ответ дан Makvin 26 August 2018 в 17:50
поделиться

Подход с общими предпочтениями бесполезен, и класс приложения не имеет доступа к активности.

Другой вариант, который я использовал, - иметь экземпляр сохраненного фрагмента и в этом случае намного больше материал может быть выполнен, особенно если вам нужен доступ к основному пользовательскому интерфейсу.

В этом примере я использовал асинтекс в сохраненном фрагменте. Мой AsyncTask имеет обратные вызовы родительской активности. Он гарантированно запускается только один раз для каждого приложения, потому что фрагмент никогда не уничтожается - воссоздается, когда одна и та же деятельность уничтожается - воссоздана. Это сохраняемый фрагмент.

public class StartupTaskFragment extends Fragment {

public interface Callbacks {
    void onPreExecute();
    void onProgressUpdate(int percent);
    void onCancelled();
    void onPostExecute();
}

public static final String TAG = "startup_task_fragment";
private Callbacks mCallbacks;
private StartupTask mTask;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    mCallbacks = (Callbacks) activity;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true); // this keeps fragment in memory even if parent activity is destroyed

    mTask = new StartupTask();
    mTask.execute();
}

@Override
public void onDetach() {
    super.onDetach();
    mCallbacks = null;
}

private class StartupTask extends AsyncTask<Void, Integer, Void> {

    @Override
    protected void onPreExecute() {
        if (mCallbacks != null) {
            mCallbacks.onPreExecute();
        }
    }

    @Override
    protected Void doInBackground(Void... ignore) {

        // do stuff here

        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... percent) {
        if (mCallbacks != null) {
            mCallbacks.onProgressUpdate(percent[0]);
        }
    }

    @Override
    protected void onCancelled() {
        if (mCallbacks != null) {
            mCallbacks.onCancelled();
        }
    }

    @Override
    protected void onPostExecute(Void ignore) {
        if (mCallbacks != null) {
            mCallbacks.onPostExecute();
        }
    }
}
}

Затем в основном (или родительском) действии, где вы хотите, чтобы этот фрагмент запуска запуска выполнялся один раз.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    FragmentManager fm = getFragmentManager();
    StartupTaskFragment st = (StartupTaskFragment) fm.findFragmentByTag(StartupTaskFragment.TAG);

    if(st == null) {
        fm.beginTransaction().add(mStartupTaskFragment = new StartupTaskFragment(), StartupTaskFragment.TAG).commit();
    }

    ...
}

Идеи для сохраненного фрагмента пришел отсюда: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html . Я просто вычислил его другие варианты использования, кроме изменений конфигурации.

4
ответ дан Poly Bug 26 August 2018 в 17:50
поделиться
      try {

          boolean firstboot = getSharedPreferences("BOOT_PREF",MODE_PRIVATE)
    .getBoolean("firstboot", true);

                    if(firstboot){
                //place your code that will run single time                  
getSharedPreferences("BOOT_PREF",MODE_PRIVATE).edit().
    putBoolean("firstboot", false)
                        .commit();


                    }
0
ответ дан Rahulkapil 26 August 2018 в 17:50
поделиться

Да, вы можете это сделать, используя концепцию Android для SharedPrefernce. Просто создайте булевский флаг и сохраните его в SharedPrefernce и проверьте его значение в методе onCreate ().

2
ответ дан Sujit 26 August 2018 в 17:50
поделиться

Я делаю это так же, как описано в другом ответе. У меня просто есть глобальная переменная в первом действии, которая соответствует номеру выпуска из манифеста. Я увеличиваю его для каждого обновления и когда чек видит большее число, он выполняет одноразовый код.

В случае успеха он записывает новый номер в общие настройки, поэтому он не будет делать это снова до следующего upgrade.

Убедитесь, что вы назначили значение по умолчанию -1, когда вы извлекаете версию из общих настроек, чтобы вы снова ошиблись на стороне запуска кода, а не запустили его и не имели обновления для своего приложения правильно.

0
ответ дан trgraglia 26 August 2018 в 17:50
поделиться

Используйте SharedPreference для этого -

  1. Если вы снова не перезапускаете свою активацию запуска после того, как ваше приложение активно, тогда в этом случае вы используете его.
  2. Используйте это на экране Splash, если вы реализуете его в приложении.
  3. Если вы не используете какой-либо всплывающий экран, вам нужно создать действие без набора представлений, а на его вызове oncreate вы можете начать обновление и начните свою основную деятельность.

вы можете использовать для этого значение счетчика или логическое значение.

Вот документ SharedPreference:

http: //developer.android.com/reference/android/content/SharedPreferences.html

0
ответ дан Vineet Shukla 26 August 2018 в 17:50
поделиться

похоже, что вам, возможно, придется сделать что-то вроде этого

PackageInfo info = getPackageManager().getPackageInfo(PACKAGE_NAME, 0);

      int currentVersion = info.versionCode;
      this.versionName = info.versionName;
      SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
      int lastVersion = prefs.getInt("version_code", 0);
      if (currentVersion > lastVersion) {
        prefs.edit().putInt("version_code", currentVersion).commit();
       //  do the activity that u would like to do once here.
   }

Вы можете делать это каждый раз, чтобы проверить, обновлено ли приложение, поэтому он запускается только один раз для обновления приложения

4
ответ дан Yashwanth Kumar 26 August 2018 в 17:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: