J'ai une activité qui doit activer l'écran (si cette option est activée) au démarrage . Donc, dans onCreate, j'ai:
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);
En utilisant ceci avec l’aide de wakelock dans le récepteur broadcasr, je peux faire en sorte que mon activité s’affiche à chaque démarrage depuis le récepteur broadcast.
Mais le problème est très étrange, le cycle de vie d'une activité appelle de cette manière, onPause () et onResume immédiatement après le début de l'activité.
Donc, le problème est au début et à la reprise appelant deux fois, avec sur arrêter d'appeler également, je veux implémenter une logique dans onStop () mais, avec un tel comportement app ne fonctionnera pas correctement.
Modifier
J'ai trouvé le problème est dû uniquement à l'indicateur FLAG_SHOW_WHEN_LOCKED. et quand l'appareil est verrouillé. et cela ne se produit que lorsque le périphérique est verrouillé avant le début de l'activité.
P.S J'utilise le gestionnaire d'alarmes avec le récepteur de diffusion, puis commence l'activité à partir du récepteur de diffusion.
Voici un commentaire de code important documenté dans ActivityThread , responsable de l'exécution des activités du processus d'application.
Nous accomplissons cela en passant par le démarrage normal (car les activités S'attendent à passer par onResume () lors de leur première exécution, Avant que leur fenêtre ne soit affichée), puis en la mettant en pause.
Juste après onResume
, la fenêtre d'activité est attachée au gestionnaire de fenêtres et onAttachedtoWindow
est invoquée. Si l'écran est allumé, la fenêtre d'activité devient active et onWindowFocusChanged
est appelé avec le paramètre true
. De docs :
Gardez à l’esprit que onResume n’est pas le meilleur indicateur que votre l'activité est visible pour l'utilisateur; une fenêtre système telle que le protège-clavier peut être en face. Utilisez onWindowFocusChanged (boolean) pour en savoir plus que votre activité est visible pour l'utilisateur
Dans le problème signalé, l'écran est désactivé. Par conséquent, la fenêtre d'activité ne sera pas activée, ce qui entraînera l'appel de la méthode onPause
de l'activité suivie de la méthode onStop
, car la fenêtre d'activité n'est pas visible.
Étant donné que l'indicateur WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
est défini dans la fenêtre d'activité, le service du gestionnaire de fenêtres active l'écran à l'aide de l'interface du gestionnaire d'alimentation. Voici le code 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;
}
...
}
Une fois l’écran allumé, onStart
et onPause
sont à nouveau appelés.
D'où: onCreate - onStart - onResume - onPause - onStop - onStart - onPause
.
Cela peut être vérifié en verrouillant le périphérique et en démarrant l'activité à l'aide de la commande adb
ou de Eclipse
.
Si vous démarrez une tâche dans onCreate
, vous devez l'arrêter dans onDestory
(si la tâche est toujours en attente). De même pour onStart
ce serait onStop
et pour onResume
ce serait onPause
.
Si vous ne pouvez pas suivre le protocole ci-dessus, vous pouvez vérifier l'état du focus de la fenêtre d'activité à l'aide de la méthode hasWindowFocus in onPause
. Normalement, l’état du focus de la fenêtre d’activité sera true dans onPause
. Dans des scénarios tels que l'écran est éteint ou l'écran est allumé avec le verrouillage du clavier affiché, le focus de la fenêtre d'activité sera faux dans 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
}
}
Vous avez dit vouloir implémenter une logique dans onStop () mais avec un tel comportement, l'application ne fonctionnerait pas correctement. vous ne nous avez pas montré ce que vous avez exactement dans onStop () mais je pense que votre logique relance probablement l’activité .. dans ce cas, vous pouvez implémenter votre logique dans onStop de la manière suivante:
@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)
}
}
}
}
une autre solution qui pourrait vous aider sera d'éviter onStop () et d'utiliser onWindowFocusChanged avec 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{
}
}
Ajoutez Android:configChanges="keyboardHidden|orientation|screenSize"
à Activity
dans votre Manifest
. Cela peut résoudre votre problème.
La solution de rechange de Manish Mulimani a fonctionné pour moi, sauf que je vérifie d’abord le focus de la fenêtre, puis que je passe au 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
}
}
J'ai remarqué qu'il y a un attribut activity
dans le AndroidManifest.xml
appelé Android:showOnLockScreen="true|false"
par exemple:
<activity Android:name="AlarmAlertFullScreen"
Android:excludeFromRecents="true"
Android:theme="@style/AlarmAlertFullScreenTheme"
Android:showOnLockScreen="true"
Android:screenOrientation="nosensor"
Android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/>
J'ai cherché sur le Web sa documentation, mais pas de chance, mais d'après son nom, il devrait fonctionner comme le drapeau Window WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
do.
le seul document que j'ai trouvé
Spécifiez qu'une activité doit être affichée sur l'écran de verrouillage et, dans un environnement multi-utilisateur, à travers les fenêtres de tous les utilisateurs [booléen]
Modifier
pouvez-vous s'il vous plaît essayer d'appeler votre code de drapeau avant d'appeler 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);
.
.
.
}
}
Essaye ça. J'ai utilisé ça et ça marche 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();