web-dev-qa-db-fra.com

Comment puis-je exécuter quelque chose juste une fois par démarrage d'application?

J'aimerais implémenter un vérificateur de mise à jour dans une application, et je n'ai évidemment besoin que de cette information pour qu'elle s'affiche une fois lorsque vous démarrez l'application. Si je fais l'appel dans la méthode onCreate() ou onStart(), il sera affiché à chaque fois que l'activité est créée et ce n'est pas une solution viable.

Ma question est donc la suivante: Y a-t-il un moyen de faire quelque chose, comme vérifier les mises à jour, juste une fois par démarrage/lancement d’application?

Je suis désolé si c'est un peu difficile à comprendre, j'ai du mal à m'expliquer à ce sujet.

22
Michell Bak

SharedPreferences me semble une solution laide. C’est beaucoup plus pratique lorsque vous utilisez le constructeur d’application à ces fins.

Tout ce dont vous avez besoin est d'utiliser votre propre classe d'application, pas celle par défaut.

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

Ensuite, vous devez enregistrer cette classe en tant que classe d'application dans 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>

Vous pouvez même appuyer sur le bouton Précédent pour que l'application passe en arrière-plan et ne gaspille pas les ressources de votre processeur, mais uniquement les ressources de mémoire. Vous pouvez ensuite le relancer et le constructeur ne se déclenche toujours pas car l'application n'est pas encore terminée.

Vous pouvez vider la mémoire dans le Gestionnaire des tâches pour que toutes les applications soient fermées, puis relancer votre application pour vous assurer que votre code d'initialisation se déclenche à nouveau.

50
Vitalii Korsakov

on dirait que vous pourriez avoir à faire quelque chose comme ça

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

Vous pouvez le faire à chaque fois pour vérifier si l'application a été mise à niveau, afin qu'elle ne s'exécute qu'une seule fois pour la mise à niveau de l'application.

4
Yashwanth Kumar

L'approche des préférences partagées est désordonnée et la classe d'applications n'a pas accès à une activité.

Une autre alternative que j'ai utilisée consiste à avoir une instance de fragment conservé. Dans cette instance, beaucoup plus de tâches peuvent être effectuées, en particulier si vous avez besoin d'accéder à l'interface utilisateur d'activité principale.

Pour cet exemple, j'ai utilisé asynctask dans le fragment retenu. Mon AsyncTask a des rappels à l'activité parente. Il est garanti qu’elle ne peut être exécutée qu’une seule fois par application car le fragment n’est jamais détruit-recréé lorsque la même activité est détruite-recréé. C'est un fragment retenu.

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

Ensuite, dans l'activité principale (ou parent) où vous souhaitez que ce fragment de tâche de démarrage s'exécute une fois.

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

    ...
}

Les idées pour le fragment retenu sont venues d'ici: http://www.androiddesignpatterns.com/13/04/retaining-objects-across-config-changes.html . Je viens de comprendre ses autres utilisations en dehors des changements de configuration.

4
Poly Bug

Oui, vous pouvez le faire en utilisant le concept SharedPreferences d’Android. Créez simplement un indicateur booléen, enregistrez-le dans Préférences partagées et vérifiez sa valeur dans votre méthode onCreate ().

2
Sujit

Je viens de résoudre ce problème moi-même, je rouvre mon activité principale plusieurs fois au cours de l'exécution de l'application. Bien que le constructeur soit une approche valable pour certaines choses, il ne vous permet pas d'accéder au contexte actuel de l'application pour écrire des toasts, entre autres}.

Ma solution a été de créer un ensemble booléen 'firstRun' simple à true dans la classe de mon MainActivity. À partir de là, je lance le contenu de l'instruction if puis le définit sur true. Exemple:

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

Utilisez SharedPreference pour cela-

  1. Si vous ne redémarrez pas votre activité de lancement une fois votre application active, utilisez-la dans ce cas.

  2. Utilisez ceci dans un écran de démarrage si vous l'implémentez dans l'application.

  3. Si vous n'utilisez pas d'écran de démarrage, vous devez créer une activité sans vue et dès la création de l'appel, vous pouvez lancer la mise à jour et démarrer votre activité principale.

vous pouvez utiliser une valeur de compteur ou un booléen pour cela.

Voici le document SharedPreference:

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

0
Vineet Shukla
 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

Je le fais de la même manière que décrit dans l'autre réponse. Je viens d'avoir une variable globale dans la première activité qui correspond au numéro de version du manifeste. Je l'incrémente pour chaque mise à niveau et, lorsque la vérification détecte un nombre plus élevé, il exécute le code à utilisation unique.

En cas de succès, il écrit le nouveau numéro dans les préférences partagées afin qu'il ne le répète pas jusqu'à la prochaine mise à niveau.

Assurez-vous d'affecter la valeur par défaut à -1 lorsque vous récupérez la version à partir des préférences partagées, de sorte que vous vous trompiez lors de l'exécution du code à nouveau, au lieu de ne pas l'exécuter et de ne pas mettre à jour correctement votre application.

0
trgraglia
      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