remove popbackstackimmediate from fragments example begintransaction backstack addtobackstack android

android - popbackstackimmediate - Despachar la acción del usuario a actividades en backstack.



onbackpressed fragment (7)

¿Para actualizar sus datos?

Aquí está la respuesta. Las actividades no deben poseer datos. Las actividades presentan datos y permiten al usuario actuar sobre ellos. Los datos en sí deben estar en una entidad separada con la que puedan interactuar las instancias de actividad, un Modelo.

Además, no se debe suponer que siempre hay una instancia de actividad en la back-stack. Esas actividades pueden ser destruidas y luego recreadas como objetos diferentes por el sistema cuando el usuario navega hacia atrás. Los datos siempre se actualizan cuando se crea toda la actividad.

Separe el manejo de datos en clases especializadas, a las que se puede acceder fácilmente mediante actividades y puede proporcionar enlace de datos / eventos a actividades bajo demanda. Un Service obligado es un buen candidato.

En lo que respecta a no cargar datos desde la web, puede configurar un caché local de los datos a los que se accedió más recientemente (caché, porque los móviles tienen límites de almacenamiento estrictos, el servidor y la base de datos no lo son). Por lo tanto, cualquier cambio desde el lado del usuario también se confirma en este caché junto con la propagación al servidor. Todo esto debe ser encapsulado por clases de datos especializadas, en lugar de confiar en una pila de reserva o un código especial en las clases de actividad.

Como patrón puede construir clases de Model para las entidades de datos involucradas. Escriba una implementación de interfaz web API para hablar con el servidor. Y luego, coloca una capa de caché antes de la interfaz API. La memoria caché retendría los cambios salientes y las actualizaciones entrantes a / desde la capa API y simplemente reflejaría las solicitudes de datos cuando no se necesita la llamada del servidor.

El caché tiene que hacer 3 cosas principalmente:

  1. Desalojar: a medida que aparezcan nuevos datos, elimine los datos menos importantes, por lo que la memoria caché permanece en un tamaño fijo. La mayoría de las implementaciones de caché ( como esta ) lo hacen automáticamente.
  2. Invalidar: Algunas veces, debido a una acción del usuario o un evento externo en el lado del servidor, algunos datos deben actualizarse.
  3. Caducidad: los datos se pueden establecer con un límite de tiempo y serán desalojados automáticamente. Esto es útil cuando se aplica una actualización periódica de datos.

Ahora la mayoría de las implementaciones de caché se tratan en bytes sin procesar. Recomiendo usar algo como Realm , una base de datos de objetos y envolverlo en características similares a caché. Por lo tanto, un flujo típico de solicitud de tweets de usuarios sería:

  1. Se muestra la actividad.
  2. La actividad se enlaza con el servicio de datos y expresa su interés en los "tweets".
  3. El servicio de datos busca en la tabla de Tweets de caché la última lista recuperada de tweets y la devuelve inmediatamente.
  4. Pero, el servicio de datos también llama al servidor para dar los tweets después de la marca de tiempo del último tweet que tiene localmente en db.
  5. El servidor devuelve el último conjunto de tweets.
  6. El servicio de datos actualiza todas las actividades vinculadas que expresaron interés en los tweets, con nuevos datos entrantes. Estos datos también se replican localmente en db caché. En este punto, la tabla de tweets también se optimiza al eliminar registros antiguos.
  7. La actividad se desvincula del servicio de datos, ya que la actividad se va, se detiene, se destruye, etc.
  8. Si ninguna actividad vinculada está interesada en los "tweets", el servicio de datos deja de cargar más tweets.

Su implementación de datos puede ir más allá al mantener las conexiones de socket al servidor y recibir cambios interesantes en tiempo real. Ese es el paso 5 anterior será llamado por el servidor siempre que haya nuevos datos entrantes.

TLDR; Separe la gestión de datos de las Actividades, y luego podrá evolucionar independientemente de las preocupaciones de la IU.

Estoy desarrollando una aplicación social. Supongamos que tengo una pila de actividades A -> B -> C -> D D está en primer plano y el usuario presiona el botón "Me gusta" para algo allí (publicación, comentario, usuario, etc.) ¿Cuál es la mejor manera de notificar a todas las demás actividades sobre esta acción para actualizar sus datos? Veo 3 opciones aquí:

  1. Utilice la base de datos local y algunos cargadores para actualizar automáticamente los datos. Sin embargo, requiere mucho código si tenemos diferentes modelos de datos con datos compartidos (por ejemplo, BasicUserInfo , UserInfo , DetailedUserInfo ).
  2. Utilice EventBus con eventos pegajosos (productores para Otto). En este caso, debo notificar SOLO las actividades de backstack e ignorar aquellas que se crearán. También tengo que gestionar eventos anulando.
  3. Use un patrón de observador simple con WeakReferences para realizar actividades de backstack. Pero luego tengo un problema con las actividades eliminadas que se van a volver a crear.

Ejemplo real:

En Instagram: abro el perfil de algún usuario específico (A), ahí abro un post específico (B), de nuevo el perfil (A) y así sucesivamente A -> B -> A -> B -> A .... Así que Carga datos desde la web cada vez. En el paso "n + 1" aparece un nuevo comentario a la publicación. Si vuelvo a revisar mi backstack, veré que Instagram ha enviado este "nuevo" comentario a todas las actividades B sin volver a cargar ningún dato de la web. Así que soy interesante cómo lo hacen.


Como muchas otras respuestas han sido eludidas, este es un ejemplo clásico en el que un BroadcastReceivers podría hacer el trabajo fácilmente.

También recomendaría usar la clase http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html junto con BroadcastReceiver. De la documentación de BroadcastReceiver:

Si no necesita enviar transmisiones a través de aplicaciones, considere usar esta clase con LocalBroadcastManager en lugar de las instalaciones más generales que se describen a continuación. Esto le dará una implementación mucho más eficiente (no se necesita comunicación entre procesos) y le permitirá evitar pensar en cualquier problema de seguridad relacionado con otras aplicaciones que puedan recibir o enviar sus transmisiones.


El caso de uso principal de un sistema de notificación (evento, observador, BroadcastReceiver , ...) es cuando desea que el destinatario actúe de forma más o menos inmediata cuando ocurre algo.

Creo que este no es el caso aquí: las actividades de backstack no necesitan actuar inmediatamente ya que no son visibles. Además pueden incluso no existir más (muertos / congelados). Lo que realmente necesitan es obtener los datos más recientes cuando vuelvan a estar en primer plano (posiblemente después de haber sido recreados).

¿Por qué no simplemente desencadenar la actualización en onStart() o onResume() (usando un Loader o cualquier cosa que ya use)?
Si el estado ''me gusta'' debe persistir, puede hacerlo en D s onPause() . De lo contrario, el objeto deseado podría almacenarse en una variable global (que en realidad es lo que es un evento pegajoso)


Estoy de acuerdo con el enfoque de @bwt. Esos sistemas de notificación deberían importar cuando quieres notificar algo inmediatamente.

Mi enfoque sería un sistema de caché. No necesita tratar con "si la actividad se ha vuelto a acumular o se ha creado de nuevo", siempre debe consultar lo que necesita en el onResume de la actividad. Por lo que siempre obtendrá los datos más actualizados.

Al recuperar datos de su servidor, también necesita una copia de sus modelos de datos en una base de datos local. Antes de hacer ping a su servidor cuando, por ejemplo, hay un "me gusta" en una publicación de usuario, debe configurar esto como un Flag en la base de datos local y enviar su solicitud Http a su servidor para que diga "Hey, esta publicación está agradecida". Y luego, cuando obtenga la respuesta de esta solicitud, si tiene éxito o no, intente modificar este indicador nuevamente.

Por lo tanto, en sus Actividades, obtendrá los datos más actualizados si realiza una consulta desde la base de datos local en onResume . Y para los cambios en la publicación de otros usuarios, puede tener un BroadcastReceiver para reflejar los cambios en su actividad visible.

PD: puede consultar Realm.io para consultas relativamente más rápidas, ya que necesitará llamadas de base de datos locales más rápido.


La forma clásica de manejar este tipo de cosas es usar BroadcastReceivers .

Aquí hay un receptor de ejemplo:

public class StuffHappenedBroadcastReciever extends BroadcastReceiver { private static final String ACTION_STUFF_HAPPENED = "stuff happened"; private final StuffHappenedListener stuffHappenedListener; public StuffHappenedBroadcastReciever(@NonNull Context context, @NonNull StuffHappenedListener stuffHappenedListener) { this.stuffHappenedListener = stuffHappenedListener; context.registerReceiver(this, new IntentFilter(ACTION_STUFF_HAPPENED)); } public static void notifyStuffHappened(Context context, Bundle data) { Intent intent = new Intent(ACTION_STUFF_HAPPENED); intent.putExtras(data); context.sendBroadcast(intent); } @Override public void onReceive(Context context, Intent intent) { stuffHappenedListener.onStuffHappened(intent.getExtras()); } public interface StuffHappenedListener { void onStuffHappened(Bundle extras); } }

Y como adjuntarlo a una actividad:

public class MainActivity extends AppCompatActivity implements StuffHappenedBroadcastReciever.StuffHappenedListener { private StuffHappenedBroadcastReciever mStuffHappenedReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mStuffHappenedReceiver = new StuffHappenedBroadcastReciever(this, this); } @Override protected void onDestroy() { unregisterReceiver(mStuffHappenedReceiver); super.onDestroy(); } @Override public void onStuffHappened(Bundle extras) { // do stuff here } }

"onStuffHappened" se llamará mientras la actividad esté viva.


Puede usar LocalBroadcastManager para notificar a sus actividades apiladas que su evento Liked ha ocurrido

Supongamos en su Actividad D:

private void liked() { Log.d("liked", "Broadcasting message"); Intent intent = new Intent("like-event"); // You can also include some extra data. intent.putExtra("message", "my like event occurs!"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); }

Ahora notificará todas las actividades que están registradas con este receptor de difusión.

por ejemplo en tu Actividad A, B, C:

@Override public void onCreate(Bundle savedInstanceState) { ... // Register to receive messages. // We are registering an observer (mMessageReceiver) to receive Intents // with actions named "custom-event-name". LocalBroadcastManager.getInstance(this).registerReceiver(mLikeEventReceiver , new IntentFilter("like-event")); } // Our handler for received Intents. This will be called whenever an Intent // with an action named "like-event" is broadcasted. private BroadcastReceiver mLikeEventReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Get extra data included in the Intent String message = intent.getStringExtra("message"); Log.d("receiver", "Got message: " + message); } }; @Override protected void onDestroy() { // Unregister since the activity is about to be closed. LocalBroadcastManager.getInstance(this).unregisterReceiver(mLikeEventReceiver ); super.onDestroy(); }

referencias: [ http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html][1] [ cómo utilizar LocalBroadcastManager? [ https://androidcookbook.com/Recipe.seam?recipeId=4547][3]

  1. [1]: http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html

  2. [2]: ¿cómo usar LocalBroadcastManager?

  3. [3]: https://androidcookbook.com/Recipe.seam?recipeId=4547


Si tiene que realizar cambios en todas las actividades con respecto a algunos datos, puede seguir el patrón de interfaz. Por ejemplo, tiene una clase de clase personalizada ActivityData que tiene el contenido que necesita actualizar en todas las actividades

Paso 1:

Crear una interfaz de la siguiente manera

public interface ActivityEventListener { ActivityData getData( Context context, Activity activity ); }

Paso 2:

Cree una BaseActivity para hacer referencia a todas las actividades de ur que tenga en su aplicación e implemente la interfaz de la siguiente manera

public class BaseActivity extends Activity { protected AcitivityData mData= null; @Override protected void onCreate( Bundle savedInstanceState ) { super.onCreate( savedInstanceState ); } protected ActivityEventListener mListener = new ActivityEventListener() { @Override public ActivityData getData( Context context, Activity activity ) { // TODO Auto-generated method stub return mData; } }; }

paso 3: amplía tu propia actividad con BaseActivity, por ejemplo, A o B o C .......

la clase pública A amplía la actividad base {

ActivityData mData; @Override protected void onCreate( Bundle savedInstanceState ) { mData = mListener.getData(this,this); updateWidgets(mData); }

}

donde updateWidgets es una función donde puede definir elementos de la interfaz de usuario y usar los datos que tiene con la interfaz

Como todas sus actividades, B / C / etc. puede obtener la referencia de ActivityData. Las actividades de backstack comenzarán a ejecutarse a través de onStart () el usuario puede manejar actividades de la misma naturaleza con los detalles existentes en ActivityData

En su caso, cuando lo desee en la última actividad, puede actualizar el objeto de ActivtyData y cuando la actividad de la contraportada se reanude o comience, puede obtener datos actualizados a medida que su actividad de backstack se extienda con la interfaz de BaseActiivty.