¿Cuál es la mejor manera de compartir datos entre actividades?

Resuelto Crazyfool asked hace 54 años • 0 respuestas

Tengo una actividad que es la actividad principal utilizada en toda la aplicación y tiene varias variables. Tengo otras dos actividades en las que me gustaría poder utilizar los datos de la primera actividad. Ahora sé que puedo hacer algo como esto:

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

Sin embargo, quiero compartir muchas variables y algunas pueden ser bastante grandes, por lo que no quiero crear copias de ellas como se muestra arriba.

¿Hay alguna manera de obtener y cambiar directamente las variables sin utilizar los métodos get y set? Recuerdo haber leído un artículo en el sitio de desarrollo de Google que decía que esto no se recomienda para el rendimiento en Android.

Crazyfool avatar Jan 01 '70 08:01 Crazyfool
Aceptado

Aquí una recopilación de las formas más comunes de lograrlo :

  • Enviar datos dentro de la intención
  • Campos estáticos
  • HashMap deWeakReferences
  • Objetos persistentes (sqlite, preferencias para compartir, archivos, etc.)

TL;DR : hay dos formas de compartir datos: pasar datos en los extras de la intención o guardarlos en otro lugar. Si los datos son primitivos, cadenas u objetos definidos por el usuario: envíelos como parte de los extras de intención (los objetos definidos por el usuario deben implementar Parcelable). Si pasa objetos complejos, guarde una instancia en un singleton en otro lugar y acceda a ellos desde la actividad iniciada.

Algunos ejemplos de cómo y por qué implementar cada enfoque:

Enviar datos dentro de intents

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

Sobre la segunda actividad:

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

Utilice este método si está pasando datos primitivos o cadenas . También puedes pasar objetos que implemente Serializable.

Aunque es tentador, deberías pensarlo dos veces antes de usarlo Serializable: es propenso a errores y terriblemente lento. Entonces, en general: manténgase alejadoSerializable si es posible. Si desea pasar objetos complejos definidos por el usuario, eche un vistazo a la Parcelableinterfaz . Es más difícil de implementar, pero tiene ganancias de velocidad considerables en comparación con Serializable.

Compartir datos sin persistir en el disco

Es posible compartir datos entre actividades guardándolos en la memoria dado que, en la mayoría de los casos, ambas actividades se ejecutan en el mismo proceso.

Nota: a veces, cuando el usuario abandona su actividad (sin salir de ella), Android puede decidir cerrar su aplicación. En tal escenario, he experimentado casos en los que Android intenta iniciar la última actividad utilizando la intención proporcionada antes de que se cerrara la aplicación. En estos casos, los datos almacenados en un singleton (ya sea el suyo o el suyo Application) desaparecerán y podrían suceder cosas malas. Para evitar tales casos, puede conservar los objetos en el disco o verificar los datos antes de usarlos para asegurarse de que sean válidos.

Utilice una clase singleton

Tener una clase para contener los datos:

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 la actividad lanzada:

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

Usar aplicación singleton

El singleton de la aplicación es una instancia android.app.Applicationque se crea cuando se inicia la aplicación. Puede proporcionar uno personalizado extendiendo 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;}
}

Antes de iniciar la actividad:

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

Luego, de la actividad lanzada:

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

Campos estáticos

La idea es básicamente la misma que la del singleton, pero en este caso proporcionas acceso estático a los datos:

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

De la actividad lanzada:

String data = DataHolder.getData();

HashMap deWeakReferences

La misma idea, pero permitiendo que el recolector de basura elimine objetos sin referencia (por ejemplo, cuando el usuario abandona la actividad):

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

Antes de iniciar la actividad:

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

De la actividad lanzada:

DataHolder.getInstance().retrieve(someId);

Es posible que tengas que pasar o no la identificación del objeto utilizando los extras de la intención. Todo depende de tu problema específico.

Persistir objetos en el disco

La idea es guardar los datos en el disco antes de iniciar la otra actividad.

Ventajas: puedes iniciar la actividad desde otros lugares y, si los datos ya persisten, debería funcionar bien.

Desventajas: es engorroso y lleva más tiempo implementarlo. Requiere más código y, por tanto, más posibilidades de introducir errores. También será mucho más lento.

Algunas de las formas de conservar objetos incluyen:

  • Guárdalos en las preferencias compartidas.
  • Guárdalos en una base de datos sqlite
  • Guárdalos en un archivo (yo evitaría este)
Cristian avatar Feb 02 '2011 18:02 Cristian

Qué puedes usar:

  1. pasar datos entre actividades (como dijo Cristian)
  2. usar una clase con muchas variables estáticas (para que pueda llamarlas sin una instancia de la clase y sin usar getter/setter)
  3. Usando una base de datos
  4. Preferencias compartidas

Lo que elijas depende de tus necesidades. Probablemente utilizarás más de una forma cuando tengas "muchos"

WarrenFaith avatar Feb 02 '2011 18:02 WarrenFaith

"Sin embargo, quiero compartir muchas variables y algunas pueden ser bastante grandes, por lo que no quiero crear copias de ellas como se muestra arriba".

Eso no hace una copia (especialmente con String , pero incluso los objetos se pasan por el valor de la referencia, no por el objeto en sí, y los captadores como ese están bien de usar, posiblemente mejores que otros medios porque son comunes y bien entendido). Los "mitos del rendimiento" más antiguos, como no utilizar captadores y definidores, todavía tienen cierto valor, pero también se han actualizado en los documentos .

Pero si no desea hacer eso, también puede hacer que las variables sean públicas o protegidas en GlobalState y acceder a ellas directamente. Y puede crear un singleton estático como indica el objeto de aplicación JavaDoc :

Normalmente no es necesario subclasificar Aplicación. En la mayoría de las situaciones, los singleton estáticos pueden proporcionar la misma funcionalidad de una manera más modular. Si su singleton necesita un contexto global (por ejemplo, para registrar receptores de transmisión), a la función para recuperarlo se le puede dar un contexto que utiliza internamente Context.getApplicationContext() cuando construye el singleton por primera vez.

El uso de datos de intención , como señalan otras respuestas aquí, es otra forma de pasar datos, pero generalmente se usa para datos más pequeños y tipos simples. Puede pasar datos más grandes/más complejos, pero es más complicado que simplemente usar un singleon estático. Sin embargo, el objeto Aplicación sigue siendo mi favorito personal para compartir datos no persistentes más grandes/complejos entre componentes de aplicaciones de Android (porque tiene un ciclo de vida bien definido en una aplicación de Android).

Además, como han señalado otros, si los datos se vuelven muy complejos y deben ser persistentes, entonces puedes usar SQLite o el sistema de archivos también.

Charlie Collins avatar Feb 02 '2011 18:02 Charlie Collins

Existe una forma nueva y mejor de compartir datos entre actividades y es LiveData . Observe en particular esta cita de la página del desarrollador de Android:

El hecho de que los objetos LiveData tengan en cuenta el ciclo de vida significa que puede compartirlos entre múltiples actividades, fragmentos y servicios. Para mantener el ejemplo simple, puede implementar la clase LiveData como un singleton

La implicación de esto es enorme: cualquier dato del modelo se puede compartir en una clase singleton común dentro de un LiveDatacontenedor. Se puede inyectar desde las actividades en sus respectivas ViewModelen aras de la capacidad de prueba. Y ya no tendrá que preocuparse por referencias débiles para evitar pérdidas de memoria.

Amir Uval avatar Nov 04 '2018 10:11 Amir Uval