android - una - OnPause y OnStop() se llaman inmediatamente después de iniciar la actividad
regresar a un activity anterior android (7)
Agregue android:configChanges="keyboardHidden|orientation|screenSize"
a su Activity
en su Manifest
. Esto puede resolver su problema.
Tengo una actividad que necesita activar la pantalla (si está desactivada) cuando se inicia. Entonces, en onCreate, tengo:
this.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
Usando esto con la ayuda de wakelock en el receptor de broadcasr, puedo hacer que mi actividad se muestre siempre que se inicie desde el receptor de difusión.
Pero el problema es muy extraño, las llamadas al ciclo de vida de la actividad de esta manera, onPause () y onResume inmediatamente después de iniciar la actividad
- onCreate
- onStart
- En resumen
- OnPause
- OnStop
- onStart
- En resumen
Así que el problema está en comenzar y en reanudar llamadas dos veces, con detener también llamadas, quiero implementar algo de lógica en onStop () pero, con tal comportamiento, la aplicación no funcionará correctamente.
Editar
Encontré que el problema solo se debe a la marca FLAG_SHOW_WHEN_LOCKED. y cuando el dispositivo está bloqueado. y solo ocurre cuando el dispositivo está bloqueado antes de que la actividad comience.
PD: estoy usando el administrador de alarmas con el receptor de difusión, y luego comienzo la actividad del receptor de difusión.
Dijiste que quieres implementar algo de lógica en onStop () pero con esa aplicación de comportamiento no funcionará correctamente. no nos mostró qué tiene exactamente dentro de Stop () pero creo que su lógica probablemente reinicia la actividad ... en ese caso puede implementar su lógica en onStop de esa manera:
@Override
protected void onStop(){
super.onStop();
//implement your code only if !STATE_OFF - to prevent infinite loop onResume <-> onStop while screen is off
DisplayManager dm = (DisplayManager) this.getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()){
if(display.getState() != Display.STATE_OFF){
//implement your code only if device is not in "locked" state
KeyguardManager myKM = (KeyguardManager) this.getSystemService(Context.KEYGUARD_SERVICE);
if( !myKM.inKeyguardRestrictedInputMode())
//If needed you can call finish() (call onDestroy()) and your logic will restart your activity only once.
finish();
// implement your logic here (your logic probably restarts the activity)
}
}
}
}
Otra solución que puede ayudarlo será evitar onStop () y usar onWindowFocusChanged con bool hasFocus
/** * Called when the current {@link Window} of the activity gains or loses * focus. This is the best indicator of whether this activity is visible * to the user. */ @Override public void onWindowFocusChanged(boolean hasFocus){ super.onWindowFocusChanged(hasFocus); if( ! hasFocus ){ } else{ } }
La solución de Manish Mulimani funcionó para mí, excepto que primero compruebo el foco de la ventana y luego llamo al super.onPause ():
public void onPause() {
mFocusDuringOnPause = hasWindowFocus();
super.onPause();
}
public void onStop() {
super.onStop();
if (mFocusDuringOnPause) {
// normal scenario
} else {
// activity was started when screen was off or screen was on with keyguard displayed
}
}
Me di cuenta de que hay un atributo de activity
en AndroidManifest.xml
llamado android:showOnLockScreen="true|false"
por ejemplo:
<activity android:name="AlarmAlertFullScreen"
android:excludeFromRecents="true"
android:theme="@style/AlarmAlertFullScreenTheme"
android:showOnLockScreen="true"
android:screenOrientation="nosensor"
android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/>
Busqué en la web su documentación pero no tuve suerte, pero por su nombre debería funcionar como lo hace la ventana Window WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
do.
el único documento que he encontrado
Especifique que se debe mostrar una actividad en la pantalla de bloqueo y, en un entorno multiusuario, en todas las ventanas de los usuarios [booleano]
Editar
¿Puedes intentar llamar a tu código de super.onCreate(...)
antes de llamar a super.onCreate(...)
public class BaseActivity extends Activity {
@Override
protected void onCreate(Bundle bundle) {
this.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
//then call super
super.onCreate(bundle);
.
.
.
}
}
Prueba esto. Lo he usado y funciona bien
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
_wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
POWER_SERVICE);
_wakeLock.acquire();
Use la clase WakeLocker. Tiene métodos para activar la pantalla
- Permítanos entender por qué los métodos del ciclo de vida se llaman varias veces.
Aquí hay un comentario importante del código documentado en ActivityThread , que es responsable de ejecutar las actividades del proceso de solicitud.
Logramos esto mediante el inicio normal (porque las actividades esperan pasar por Reencender () la primera vez que se ejecutan, antes de que se muestre su ventana), y luego pausarlo.
Inmediatamente después de onResume
, la ventana de actividad se adjunta al administrador de ventanas y se invoca onAttachedtoWindow
. Si la pantalla está encendida, la ventana de actividad obtendrá el foco y onWindowFocusChanged
se invoca con el parámetro true
. De docs :
Tenga en cuenta que onResume no es el mejor indicador de que su actividad es visible para el usuario; una ventana del sistema como el bloqueo de teclas puede estar en frente. Use onWindowFocusChanged (boolean) para asegurarse de que su actividad sea visible para el usuario
En el problema informado, la pantalla está apagada. Por lo tanto, la ventana de actividad no obtendrá el foco, lo que da como resultado que se onPause
método onPause
la actividad seguido por el método onStop
, ya que la ventana de actividad no está visible.
Dado que el indicador WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
se establece en la ventana de actividad, el servicio del administrador de ventanas enciende la pantalla mediante la API de administrador de energía. A continuación se muestra el código de WindowManagerService :
public int relayoutWindow(...) {
...
toBeDisplayed = !win.isVisibleLw();
...
if (toBeDisplayed) {
...
if ((win.mAttrs.flags
& WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Relayout window turning screen on: " + win);
win.mTurnOnScreen = true;
}
...
if (mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
mPowerManager.wakeUp(SystemClock.uptimeMillis());
mTurnOnScreen = false;
}
...
}
Después de que la pantalla se enciende, se onStart
y onPause
nuevamente.
Por lo tanto: onCreate - onStart - onResume - onPause - onStop - onStart - onPause
.
Esto se puede verificar bloqueando el dispositivo y comenzando la actividad usando el comando adb
o eclipse
.
- Solución ideal
Si inicia una tarea en onCreate
, debe detenerla en onDestory
(si la tarea aún está pendiente). Del mismo modo para onStart
sería onStop
y para onResume
sería onPause
.
- Solución
Si no puede seguir el protocolo anterior, puede verificar el estado del enfoque de la ventana de actividad usando hasWindowFocus en el método onPause
. Normalmente, el estado de enfoque de la ventana de actividad será verdadero en onPause
. En escenarios como la pantalla está apagada o la pantalla está encendida con el bloqueo del teclado mostrado, el foco de la ventana de actividad será falso en onPause
.
boolean mFocusDuringOnPause;
public void onPause() {
super.onPause;
mFocusDuringOnPause = hasWindowFocus();
}
public void onStop() {
super.onStop();
if(mFocusDuringOnPause) {
// normal scenario
} else {
// activity was started when screen was off / screen was on with keygaurd displayed
}
}