java - proyecto - descarga de launch4j
¿Por qué las devoluciones de llamada ejecutables destruyen la actividad automáticamente? (8)
Creo que deberías invertir la lógica en el programa. La actividad debe comenzar desde sus actividades, no desde el servicio.
Para lograrlo, puede registrar BroadcastReceiver en la creación de cada actividad https://developer.android.com/reference/android/content/BroadcastReceiver.html y usar sendBroadcast desde el servicio https://developer.android.com/guide/components /broadcasts.html cuando se necesita iniciar una actividad, para ordenar al receptor de difusión que inicie la actividad necesaria.
Quería saber si existe la posibilidad de que podamos manejar / detectar devoluciones de llamada ejecutables con retraso (método postDelayed
) en android?
Por ejemplo, tengo una o varias splashscreen (que se ejecuta con handler.postDelayed(new Runnable()...
) en mi aplicación (aplicación para fines de prueba). En esta aplicación también tengo una biblioteca (que estoy creando y usando en la aplicación) y algunas clases que están disponibles allí que se ejecuta en una clase IntentService
.
A veces, cuando la aplicación ejecuta esas actividades de splashscreen
(para Testing purpose
), la biblioteca que estoy creando puede mostrar algunas actividades automáticamente en la interfaz de usuario. Pero parece que si esas actividades aparecen en una pantalla de bienvenida y se destruye la pantalla secundaria, esas actividades (que se abren automáticamente) también se destruirán y se registrará un mensaje de "ventana filtrada" en el logcat.
El problema es ese :
- aquellas actividades que aparecen automáticamente en la IU no deben cerrarse automáticamente, esto está prohibido. Necesita una interacción del usuario para cerrar esa actividad y vuelve al comportamiento normal de la aplicación.
- Además, la biblioteca no sabe nada sobre la interfaz de usuario de la aplicación.
Así que mis preguntas son (relativamente al lado de la biblioteca que estoy creando sin tener información sobre el flujo de la aplicación UI):
- ¿Hay alguna manera de detectar si se creó algún método postDelayed en la aplicación en relación con el lado de la Biblioteca? Si es así, ¿cómo podría manejar el problema?
PD: Tenga en cuenta que, normalmente, estoy usando un cuadro de diálogo para la actividad de suposición que aparece automáticamente.
ACTUALIZAR
Explicación del diagrama:
Ahora mismo tengo un caso de que se está ejecutando un Splashscreen .
La clase que amplía la clase IntentService ha recibido una Solicitud de Internet que iniciará una Actividad .
Mientras tanto, la postdelayed
encuentra postdelayed
, la otra actividad se ha creado y se muestra en la interfaz de usuario. Cuando hayan transcurrido X segundos y la otra actividad no haya sido destruida, se creará la actividad siguiente y destruirá la otra actividad automáticamente. Al hacer eso, Android lanza un mensaje de "ventana filtrada" relativamente a la Actividad .
Necesitas explicar el problema mejor. Estoy confundido entre la relación de la pantalla de presentación y las otras actividades, y si el problema está relacionado con postDelayed()
o con el ciclo de vida de las actividades. Sugeriría un pequeño diagrama gráfico que explique qué actividades inician otras.
En cuanto a postDelayed()
, en general, si lo haces
mHandler.postDelayed(new Runnable() { ... });
Está publicando un runnable nuevo y anónimo cada vez, por lo que no podrá eliminarlo. Sugeriría el siguiente enfoque, declarando los Runnables como miembros de la clase dentro de tu biblioteca:
Runnable mLaunchSplashRunnable = new Runnable() { ... };
Runnable mLaunchContactsRunnable = new Runnable() { ... };
.
.
mHandler.postDelayed (mLaunchSplashRunnable, DELAY);
mHandler.postDelayed (mLaunchContactsRunnable, DELAY);
.
.
Como los elementos ejecutables ahora no son anónimos, puede eliminarlos de la cola en cualquier momento:
void removeLibraryDelayedRunnables() {
mHandler.removeCallbacks(mLaunchSplashRunnable);
mHandler.removeCallbacks(mLaunchContactsRunnable);
}
Tenga en cuenta que el método anterior no fallará si no hay ejecutables publicados, por lo que es seguro llamarlo en cualquier momento.
Un método para consultar el Runnable
si un Runnable
específico está en cola, afaik, no existe, pero puede usar un indicador boolean
, establecerlo cuando el ejecutable está en cola y restablecerlo cuando Runnable
se ejecuta, para indicar que un ejecutable es pendiente.
Si entiendo mejor tu problema, podré ayudarte más.
¿Hay alguna manera de detectar si se creó algún método postDelayed en la aplicación en relación con el lado de la biblioteca?
Puede hacer uso de la API MessageQueue.IdleHandler
. Vea LooperIdlingResource
cómo el expreso averigua si es el momento apropiado para disparar en la afirmación.
@Override
public boolean queueIdle() {
QueueState queueState = myInterrogator.determineQueueState();
if (queueState == QueueState.EMPTY || queueState == QueueState.TASK_DUE_LONG) {
...
} else if (queueState == QueueState.BARRIER) {
...
}
return true;
}
Esto lo ayudará a comprender si hay un mensaje en MessageQueue
, pero no le indicará qué mensaje exacto hay allí.
La solución que iría sería Runnable
el Runnable
que ha postDelayed
dentro de onStop
de la actividad, porque si la Activity
(la de la biblioteca) se ha iniciado, SplashScreen
se llama a onStop
of SplashScreen
:
public class SplashActivity extends AppCompatActivity {
private final Runnable myRunnable = () -> {
// launch `NextActivity`
};
private final Handler handler = new Handler();
@Override protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
handler.postDelayed(myRunnable, 3000);
}
@Override
protected void onStop() {
super.onStop();
handler.removeCallbacks(myRunnable);
}
}
¿Por qué no utiliza la variable booleana estática para determinar si su pantalla de inicio se está ejecutando o no cuando está a punto de llamarlo?
Como aún no vimos tu código. Mi respuesta va a ser demasiado genérica, lo siento mucho por eso.
Creo que primero deberías verificar Logcat para ver si hay alguna excepción que cierre esas actividades. Si no hay nada al respecto Simplemente verifique todos los bloques de captura de prueba para estar seguro de ello. Entonces, después de estar seguro de que no se trata de ninguna excepción de ningún tipo, verifique que el archivo AndroidManifest vea ''Iniciar modos'' de actividades. También podría provocar un cierre automático.
Si todas sus actividades están en un modo estándar, intente cambiar al menos un modo de inicio de actividades para desactivarlo e intentarlo de nuevo. Si esto no tiene ningún sentido, verifique el código de las llamadas a finish ().
Todavía no hay suerte? Entonces supongo que este podría ser un caso de ANR. Debería verificar si hay fugas de memoria que congelen su aplicación y probablemente cierre actividades. Probablemente esos ejecutables están de alguna manera arruinando su aplicación.
Creo que deberías tener un mecanismo como Eventbus o receptor de difusión para la comunicación interna entre tus pantallas. Se ejecutarán en el ciclo de vida de sus actividades y no darán lugar a ningún tipo de excepción o anr.
Las actividades se pueden destruir en cualquier momento, por lo tanto, cuando esto sucede, debe ocuparse de los diálogos que también se destruyen. En el ciclo de vida de la actividad, tendrás que destruir los "cuadros de diálogo"; de lo contrario, obtendrás la "ventana escaneada".
Además, los cuadros de diálogo que hacen referencia a las actividades se beneficiarían del uso de una Referencia débil a las actividades, luego utilizaría la referencia débil para informar las acciones de los usuarios a la actividad.
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
listener = new WeakReference<>((MyActionListener) activity);
activityWeakReference = new WeakReference<>(activity);
}
Antes de mostrar un cuadro de diálogo, también me aseguro de que la actividad no esté en proceso de finalización:
if (myActivityWeakReference.get() != null && !myActivityWeakReference.get().isFinishing()) {
// show dialog
}
Luego, cuando desee controlar la rotación del dispositivo, donde las Actividades se vuelven a crear, puede usar lo siguiente junto con sus diálogos:
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
/**
* Prevent the dialog being dismissed when rotated, when using setRetainInstance
*/
@Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance()) {
getDialog().setDismissMessage(null);
}
super.onDestroyView();
}
Usar una devolución de llamada con una actividad acoplada temporalmente puede no ser un muy buen diseño para su SDK. Considere el uso de observaciones para obtener datos de la capa de red a una actividad que necesita los datos.
Al agregar un observador a la actividad que necesita los datos, que mira para ver si se realiza la llamada de red, solo expone los datos a un observador que está activo. De esta manera, si la actividad se cierra antes de que se complete la llamada, no hay "empuje" de los datos a la actividad cerrada.
Esto también le permite crear referencias débiles a su biblioteca de manera que no tenga que preocuparse por las ventanas con pérdidas
El problema es que una vez que comienzas a disparar actividades una tras otra, después de un tiempo cuando la aplicación ha consumido mucha memoria, Android asume que las actividades anteriores se pueden destruir para optimizar el sistema y evitar la desaceleración del dispositivo, así es como funcionan los dispositivos móviles , por lo que el sistema destruye su actividad principal, que consume API. Comprenda el ciclo de vida de la actividad:
https://developer.android.com/guide/components/activities/activity-lifecycle.html
ver después de onStop () ... este es el caso con su aplicación.
Espero que esto te ayudará...