web-dev-qa-db-fra.com

Quel est le meilleur moyen de partager des données entre les activités?

J'ai une activité qui est la principale activité utilisée dans l'application et comporte un certain nombre de variables. J'ai deux autres activités pour lesquelles j'aimerais pouvoir utiliser les données de la première activité. Maintenant je sais que je peux faire quelque chose comme ça:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

Cependant, je souhaite partager un grand nombre de variables et certaines peuvent être assez volumineuses, je ne souhaite donc pas en créer de copies comme ci-dessus.

Existe-t-il un moyen d'obtenir et de modifier directement les variables sans utiliser les méthodes get et set? Je me souviens d’avoir lu un article sur le site Google dev qui disait que ce n’était pas recommandé pour une performance sous Android.

230
Crazyfool

Voici une compilation de moyens les plus courants pour y parvenir :

  • Envoyer des données à l'intérieur de l'intention
  • Champs statiques
  • HashMap of WeakReferences
  • Objets persistants (sqlite, préférences de partage, fichier, etc.)

TL; DR : il existe deux façons de partager des données: transmettre des données dans les extras de l’intention ou les sauvegarder ailleurs. Si les données sont des primitives, des chaînes ou des objets définis par l'utilisateur, envoyez-les dans le cadre des extras d'intention (les objets définis par l'utilisateur doivent implémenter Parcelable). Si vous transmettez des objets complexes, enregistrez une instance dans un singleton ailleurs et accédez-y à partir de l'activité lancée.

Quelques exemples de comment et pourquoi mettre en œuvre chaque approche:

Envoyer des données dans les intentions

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

Sur la deuxième activité:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

Utilisez cette méthode si vous transmettez des données primitives ou des chaînes . Vous pouvez également transmettre des objets qui implémentent Serializable.

Bien que tentant, vous devriez réfléchir à deux fois avant d'utiliser Serializable: il est sujet aux erreurs et horriblement lent. Donc en général: restez loin de Serializable si possible. Si vous souhaitez transmettre des objets complexes définis par l'utilisateur, , consultez l'interface Parcelable. C'est plus difficile à mettre en œuvre, mais il offre des gains de vitesse considérables par rapport à Serializable.

Partager des données sans persister sur le disque

Il est possible de partager des données entre des activités en les enregistrant en mémoire, étant donné que, dans la plupart des cas, les deux activités sont exécutées dans le même processus.

Remarque: Parfois, lorsque l'utilisateur quitte votre activité (sans le quitter), Android peut décider de tuer votre application. Dans un tel scénario, j’ai rencontré des cas dans lesquels Android tente de lancer la dernière activité en utilisant l’intention fournie avant que l’application ne soit supprimée. Dans ce cas, les données stockées dans un singleton (le vôtre ou Application) disparaîtront et de mauvaises choses pourraient arriver. Pour éviter de tels cas, vous devez soit conserver les objets sur le disque, soit vérifier les données avant de les utiliser pour vous assurer de leur validité.

Utilisez une classe singleton

Avoir une classe pour contenir les données:

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

De l'activité lancée:

String data = DataHolder.getInstance().getData();

Utiliser l'application singleton

Le singleton d'application est une instance de Android.app.Application qui est créée au lancement de l'application. Vous pouvez en fournir un personnalisé en étendant Application:

import Android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

Avant de lancer l'activité:

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

Ensuite, à partir de l'activité lancée:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

Champs statiques

L'idée est fondamentalement la même que celle du singleton, mais dans ce cas, vous fournissez un accès statique aux données:

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static String setData(String data) {DataHolder.data = data;}
}

De l'activité lancée:

String data = DataHolder.getData();

HashMap of WeakReferences

Même idée, mais en autorisant le ramasse-miettes à supprimer les objets non référencés (par exemple, lorsque l'utilisateur quitte l'activité):

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

Avant de lancer l'activité:

DataHolder.getInstance().save(someId, someObject);

De l'activité lancée:

DataHolder.getInstance().retrieve(someId);

Vous pouvez ou non passer l’identifiant d’objet en utilisant les extras de l’intention. Tout dépend de votre problème spécifique.

Persister des objets sur le disque

L'idée est de sauvegarder les données sur le disque avant de lancer l'autre activité.

Avantages: vous pouvez lancer l'activité à partir d'autres emplacements et, si les données sont déjà conservées, cela devrait fonctionner correctement.

Inconvénients: c’est lourd et sa mise en oeuvre prend plus de temps. Nécessite plus de code et donc plus de chance d'introduire des bugs. Ce sera aussi beaucoup plus lent.

Parmi les moyens de persister des objets, citons:

461
Cristian

Ce que vous pouvez utiliser:

  1. transmission de données entre activités (comme dit Cristian)
  2. en utilisant une classe avec beaucoup de variables statiques (vous pouvez donc les appeler sans instance de la classe et sans utiliser getter/setter)
  3. Utiliser une base de données
  4. Préférences partagées

Ce que vous choisissez dépend de vos besoins. Vous utiliserez probablement plus d’une façon quand vous avez "beaucoup"

22
WarrenFaith

Faites ce que Google vous commande de faire! ici: http://developer.Android.com/resources/faq/framework.html#

  • Types de données primitifs
  • Objets non persistants
  • Cours Singleton - mon préféré: D
  • Un champ/méthode statique public
  • Une carte de hachage des références faibles aux objets
  • Objets persistants (préférences de l'application, fichiers, contentProviders, base de données SQLite)
16
Tylko Arka Gdynia

"Cependant, je veux partager beaucoup de variables et certaines peuvent être assez volumineuses, donc je ne veux pas en créer de copies comme ci-dessus."

Cela ne fait pas de copie (surtout avec String , mais même les objets sont passés par la valeur de la référence, pas l'objet lui-même, et le getter est comme ça sont corrects à utiliser - peut-être mieux à utiliser que d’autres moyens car ils sont communs et bien compris). Les anciens "mythes de performance", tels que ne pas utiliser de getters et de setters, ont toujours une certaine valeur, mais ont également été mis à jour dans la documentation .

Mais si vous ne voulez pas faire cela, vous pouvez également rendre les variables publiques ou protégées dans GlobalState et y accéder directement. Et, vous pouvez créer un singleton statique comme L'application Application JavaDoc indique :

Il n’est normalement pas nécessaire de sous-classer Application. Dans la plupart des cas, les singletons statiques peuvent fournir les mêmes fonctionnalités de manière plus modulaire. Si votre singleton a besoin d'un contexte global (par exemple, pour enregistrer des récepteurs de diffusion), vous pouvez attribuer à la fonction de récupération un contexte utilisant en interne Context.getApplicationContext () lors de la première construction du singleton.

Utilisation de Intention comme autre réponse, notez que ceci est un autre moyen de transmettre des données, mais il est généralement utilisé pour des données plus petites et des types simples. Vous pouvez transmettre des données plus volumineuses/plus complexes, mais ces opérations sont plus complexes que l’utilisation d’un singleon statique. L’objet Application reste mon préféré pour le partage de données non persistantes plus volumineuses/plus complexes entre les composants de l’application Android (car son cycle de vie est bien défini dans une application Android). .

En outre, comme d’autres l'ont fait remarquer, si les données deviennent très complexes et doivent être persistantes , vous pouvez également utiliser SQLite ou le système de fichiers.

14
Charlie Collins

Vous pouvez étendre la classe Application et étiqueter tous les objets que vous voulez, ils sont alors disponibles n'importe où dans votre application.

7
Jimmy

Il existe un moyen nouveau et meilleur de partager des données entre activités, et il s’agit de LiveData . Notez en particulier cette citation de la page du développeur Android:

Le fait que les objets LiveData soient sensibles au cycle de vie signifie que vous pouvez les partager entre plusieurs activités, fragments et services. Pour que l'exemple reste simple, vous pouvez implémenter la classe LiveData en tant que singleton

L'implication de cela est énorme - toutes les données de modèle peuvent être partagées dans une classe singleton commune dans un wrapper LiveData. Il peut être injecté à partir des activités dans leurs noms respectifs ViewModel à des fins de testabilité. Et vous n'avez plus besoin de vous soucier des références faibles pour éviter les fuites de mémoire.

2
Amir Uval

Il existe différentes façons de partager des données entre les activités

1: transmission de données entre activités à l'aide de l'intention

Intent intent=new Intent(this, desirableActivity.class);
intent.putExtra("KEY", "Value");
startActivity(intent)

2: à l'aide d'un mot clé static, définissez la variable en tant que statique publique et utilisez n'importe où dans le projet

      public static int sInitialValue=0;

utiliser n'importe où dans le projet en utilisant classname.variableName;

3: Utiliser la base de données

mais comme son processus est long, vous devez utiliser une requête pour insérer des données et itérer des données en utilisant le curseur lorsque vous en avez besoin. Mais il n'y a aucune chance de perdre des données sans nettoyer le cache.

4: Utiliser les préférences partagées

beaucoup plus facile que la base de données. mais il y a certaines limitations que vous ne pouvez pas enregistrer les objets ArrayList, List et custome.

5: Créez un poseur getter dans la classe d’application et accédez à n’importe où dans le projet.

      private String data;
      public String getData() {
          return data;
      }

      public void setData(String data) {
          this.data = data;
      }

ici définir et obtenir des activités

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();  
2
vikas singh

Utiliser la table de hachage de l'approche de référence faible, décrite ci-dessus, et dans http://developer.Android.com/guide/faq/framework.html me semble problématique. Comment les entrées entières sont-elles récupérées, pas seulement la valeur de la carte? Dans quelle portée le répartissez-vous? Dans la mesure où le cadre contrôle le cycle de vie de l'activité, le fait de posséder l'une des activités participantes présente des risques d'exécution lorsque le propriétaire est détruit avant ses clients. Si l'application en est propriétaire, une activité doit explicitement supprimer l'entrée pour éviter que la table de hachage ne conserve des entrées avec une clé valide et une référence faible potentiellement endommagée. De plus, que doit faire un client lorsque la valeur renvoyée pour une clé est null?

Il me semble qu'un WeakHashMap appartenant à l'Application ou à un singleton est un meilleur choix. Un objet clé permet d’accéder à une valeur de la carte. Lorsqu'il n’existe aucune référence forte à la clé (c’est-à-dire que toutes les activités sont effectuées avec la clé et ce qui y est mappé), le GC peut récupérer l’entrée de la carte.

2
Mark Rosenberg

Partage de données entre activités exemple en passant un email après la connexion

"email" est le nom qui peut être utilisé pour référencer la valeur de l'activité demandée

1 code sur la page de connexion

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

2 code sur la page d'accueil

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
1
jeff

Eh bien, j'ai quelques idées, mais je ne sais pas si elles correspondent à vos attentes.

Vous pouvez utiliser un service contenant toutes les données, puis lier vos activités au service pour la récupération de données.

Vous pouvez également regrouper vos données dans un fichier sérialisable ou parcellaire, les attacher à un ensemble et le transmettre entre les activités.

Celui-ci ne correspond peut-être pas à vos attentes, mais vous pouvez également essayer d'utiliser une référence partagée ou une préférence en général.

De toute façon laissez-moi savoir ce que vous décidez.

1
ahodder

En supposant que vous appeliez l'activité deux de l'activité un à l'aide d'une intention.
Vous pouvez transmettre les données avec intent.putExtra (),

Prenez ceci pour votre référence. Envoi de tableaux avec Intent.putExtra

J'espère que c'est ce que tu veux.

1
Manish Khot

Toutes les réponses mentionnées ci-dessus sont excellentes ... J'ajoute simplement une réponse que personne n'avait encore mentionnée concernant la persistance de données via des activités. Il s'agit d'utiliser la base de données intégrée Android SQLite pour conserver les données pertinentes ... En fait, vous pouvez placer votre databaseHelper dans l’état de l’application et l’appeler selon vos besoins tout au long des activations. Ou tout simplement créer une classe d’aide et effectuer les appels de base de données en cas de besoin ... Ajoutez simplement une autre couche à considérer ... des autres réponses suffirait aussi .. Vraiment juste préférence

1
avatar

Si votre intention est d'appeler d'autres activités de l'activité en cours, vous devez utiliser Intentions . Vous pouvez vous concentrer moins sur la persistance de données que sur leur partage au besoin.

Cependant, si vous devez réellement conserver ces valeurs, vous pouvez les conserver dans un fichier texte structuré ou dans une base de données stockée localement. Un fichier de propriétés, un fichier XML ou un fichier JSON peut stocker vos données et être facilement analysé lors de la création de l'activité. N'oubliez pas non plus que vous avez SQLite sur tous les appareils Android, vous pouvez donc les stocker dans une table de base de données. Vous pouvez également utiliser une mappe pour stocker des paires clé-valeur et pour sérialiser la mappe sur un stockage local, mais cela peut s'avérer trop fastidieux pour être utile pour des structures de données simples.

1
Mike Yockey

Et si vous voulez travailler avec un objet de données, ces deux implémentations sont très importantes:

Serializable vs Parcelable

  • Serializable est une interface de marqueur, ce qui implique que l'utilisateur ne peut pas rassembler les données en fonction de ses besoins. Ainsi, lorsque l’objet implémente Serializable Java, il sera automatiquement sérialisé.
  • Parcelable est Android propre protocole de sérialisation. Dans Parcelable, les développeurs écrivent du code personnalisé pour le marshaling et le démultiplication. Donc, il crée moins d'objets usés par rapport à la sérialisation
  • Les performances de Parcelable sont très élevées par rapport à Serializable en raison de son implémentation personnalisée. Il est fortement recommandé d'utiliser l'implantation Parcelable lors de la sérialisation d'objets dans Android.

public class User implements Parcelable

vérifier plus dans ici

0
Diego Venâncio