起動時に画面をオンにする(オフにする場合)必要があるアクティビティがあります。 onCreateでは、次のことができます。
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);
これをbroadcasrレシーバーのwakelockの助けを借りて使用すると、ブロードキャストレシーバーから開始されるたびにアクティビティを表示することができます。
しかし、問題は非常に奇妙です。アクティビティのライフサイクルは、アクティビティを開始した直後にこの方法でonPause()およびonResumeを呼び出します
したがって、問題は開始時と再開時の2回の呼び出しであり、停止時の呼び出しもあるため、onStop()にロジックを実装したいのですが、このような動作ではアプリは正しく動作しません。
編集
問題はフラグFLAG_SHOW_WHEN_LOCKEDのみが原因であることがわかりました。デバイスがロックされているとき。アクティビティが開始される前にデバイスがロックされている場合にのみ発生します。
追伸:ブロードキャストレシーバーでアラームマネージャーを使用してから、ブロードキャストレシーバーからアクティビティを開始します。
ActivityThread で文書化された重要なコードコメントを次に示します。これは、アプリケーションプロセスのアクティビティの実行を担当します。
これは、通常のスタートアップ(アクティビティが初めて実行されたときに、ウィンドウが表示される前にonResume()を実行することを想定しているため)を実行し、それを一時停止することで実現します。
onResume
の直後に、アクティビティウィンドウがウィンドウマネージャーにアタッチされ、onAttachedtoWindow
が呼び出されます。画面がオンの場合、アクティビティウィンドウがフォーカスを取得し、onWindowFocusChanged
パラメーターでtrue
が呼び出されます。 docs から:
OnResumeは、アクティビティがユーザーに表示される最良の指標ではないことに注意してください。キーガードなどのシステムウィンドウが前面にある場合があります。 onWindowFocusChanged(boolean)を使用して、アクティビティがユーザーに表示されていることを確認します
報告された問題では、画面がオフの場合。したがって、アクティビティウィンドウはフォーカスを取得しません。アクティビティウィンドウは表示されないため、アクティビティのonPause
メソッドが呼び出され、その後にonStop
メソッドが呼び出されます。
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
フラグはアクティビティウィンドウに設定され、ウィンドウマネージャーサービスは電源マネージャーAPIを使用して画面をオンにします。 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;
}
...
}
画面がオンになった後、onStart
とonPause
が再度呼び出されます。
したがって:onCreate - onStart - onResume - onPause - onStop - onStart - onPause
。
これは、デバイスをロックし、adb
コマンドまたはEclipse
を使用してアクティビティを開始することで確認できます。
onCreate
でタスクを開始する場合は、onDestory
で停止する必要があります(タスクがまだ保留中の場合)。同様に、onStart
の場合はonStop
になり、onResume
の場合はonPause
になります。
上記のプロトコルに従わない場合は、onPause
メソッドで hasWindowFocus を使用して、アクティビティウィンドウのフォーカスのステータスを確認できます。通常、アクティビティウィンドウのフォーカスステータスはonPause
でtrueになります。画面がオフまたは画面がオンで、キーガードが表示されているシナリオでは、onPause
でアクティビティウィンドウのフォーカスがfalseになります。
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
}
}
Manish Mulimaniによる回避策は、最初にウィンドウフォーカスをチェックしてから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
}
}
OnStop()でいくつかのロジックを実装したいが、そのような動作ではアプリは正しく動作しません。 onStop()内の正確な内容は表示されませんでしたが、おそらくロジックがアクティビティを再開すると思います。その場合、onStopでロジックを実装できます。
@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)
}
}
}
}
onStop()を避け、bool hasFocusでonWindowFocusChangedを使用するのに役立つ他のソリューション
/**
* 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{
}
}
追加 Android:configChanges="keyboardHidden|orientation|screenSize"
あなたへActivity
をManifest
に。これで問題が解決する場合があります。
_AndroidManifest.xml
_に_Android:showOnLockScreen="true|false"
_というactivity
属性があることに気づきました
例えば:
_ <activity Android:name="AlarmAlertFullScreen"
Android:excludeFromRecents="true"
Android:theme="@style/AlarmAlertFullScreenTheme"
Android:showOnLockScreen="true"
Android:screenOrientation="nosensor"
Android:configChanges="orientation|screenSize|keyboardHidden|keyboard|navigation"/>
_
Webでドキュメントを検索しましたが、運はありませんでしたが、その名前からは、Windowフラグ_WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
_ doとして機能するはずです。
私が見つけた唯一の文書
アクティビティをロック画面に表示し、マルチユーザー環境ではすべてのユーザーのウィンドウに表示することを指定します[ブール]
編集
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);
.
.
.
}
}
_
これを試して。私はこれを使用しましたが、うまくいきます
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();