バックグラウンドで言うと、アプリケーションのアクティビティは現在、ユーザーには表示されていません。
バックグラウンドで言うと、アプリケーションのアクティビティは現在、ユーザーには表示されていません。
回答:
アプリケーションがバックグラウンドで実行されているかどうかを検出する方法はいくつかありますが、完全に信頼できるのはそのうちの1つだけです。
適切なソリューション(クレジットに行くダン、CommonsWareとNeTeInStEiN)
使用して自分で自分のアプリケーションのトラックの可視性Activity.onPause、Activity.onResume方法を。「可視性」ステータスを他のクラスに保存します。Applicationまたはの独自の実装が適切な選択肢ですService(サービスからアクティビティの可視性を確認する場合は、このソリューションのバリエーションもいくつかあります)。
例
カスタムApplicationクラスを実装する(isActivityVisible()静的メソッドに注意):
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
にアプリケーションクラスを登録しますAndroidManifest.xml。
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
プロジェクト内のすべてにを追加onPauseします(必要に応じて、アクティビティの共通の祖先を作成できますが、アクティビティが/ などから既に拡張されている場合は、手動で次のように記述する必要があります)。onResumeActivityMapActivityListActivity
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
アップデート
ActivityLifecycleCallbacksは、APIレベル14(Android 4.0)で追加されました。それらを使用して、アプリケーションのアクティビティが現在ユーザーに表示されているかどうかを追跡できます。詳細については、以下の Cornstalksの回答を確認してください。
次の解決策を提案するために私が使用した間違ったもの:
レコードの
ActivityManager.getRunningAppProcesses()リストを返す現在のフォアグラウンド/バックグラウンドアプリケーションを検出できますRunningAppProcessInfo。アプリケーションがフォアグラウンドチェックRunningAppProcessInfo.importanceフィールドにあるかどうかを確認するには、RunningAppProcessInfo.IMPORTANCE_FOREGROUNDwhileRunningAppProcessInfo.processNameがアプリケーションパッケージ名と等しいかどうかを確認します。また
ActivityManager.getRunningAppProcesses()、アプリケーションUIスレッドから呼び出すと、IMPORTANCE_FOREGROUND実際にフォアグラウンドにあるかどうかに関係なく、タスクの重要性が返されます。バックグラウンドスレッドで(たとえばを介してAsyncTask)呼び出すと、正しい結果が返されます。
このソリューションは機能する可能性があります(実際、ほとんどの場合機能します)が、使用は控えることを強くお勧めします。そして、これが理由です。ダイアン・ハックボーンが書いたように:
これらのAPIは、アプリケーションがUIフローのベースにするためのものではなく、実行中のアプリやタスクマネージャーなどをユーザーに表示するためのものです。
はい、これらのためにメモリに保持されているリストがあります。ただし、別のプロセスではオフであり、別のプロセスで管理されており、スレッドとは別のスレッドで実行されているため、(a)正しい判断を下すために時間内に確認したり、(b)戻ってくるまでに一貫した状況を把握したりできません。さらに、「次の」アクティビティに何をするかについての決定は、切り替えが発生するポイントで常に行われ、その正確なポイント(アクティビティ状態が切り替えを行うために短時間ロックダウンされる)までは行われません。実際に次のことがどうなるかを確実に知っています。
ここでの実装とグローバルな動作は、将来同じであるとは限りません。
私がSOに回答を投稿する前にこれを読んでいたらいいのですが、うまくいけば、私のエラーを認めるには遅すぎません。
回答の1つで言及されている別の間違ったソリューション
Droid-FuライブラリはActivityManager.getRunningTasks、そのisApplicationBroughtToBackground方法に使用しています。上記のダイアンのコメントを参照してください。その方法も使用しないでください。
OnStopへの要請に応じてisActivityVisible。
user1269737の答えは、これを行う適切な(Google / Android承認済みの)方法です。彼らの答えを読んで、彼らに+1を与えてください。
元の答えは後世のためここに残しておきます。これは2012年に利用可能な最高のものでしたが、現在Androidはこれを適切にサポートしています。
キーを使用していますActivityLifecycleCallbacks(これにはAndroid APIレベル14(Android 4.0)が必要です)。停止したアクティビティの数が開始したアクティビティの数と等しいかどうかを確認してください。それらが等しい場合、アプリケーションはバックグラウンドで実行されています。開始済みのアクティビティがさらにある場合でも、アプリケーションは表示されます。一時停止されたアクティビティよりも再開されたアクティビティが多い場合、アプリケーションは表示されるだけでなく、フォアグラウンドにも表示されます。アクティビティは、主に3つの状態に分けられます。表示と前景、表示はあるが前景は表示されず、非表示と前景は非表示です(つまり、バックグラウンド)。
このメソッドの本当に良い点は、非同期の問題getRunningTasks()がありませんが、すべてを変更する必要がないことですActivity、アプリケーションのしてonResumed()/で何かを設定/設定解除onPaused()です。自己完結型のコードはほんの数行であり、アプリケーション全体で機能します。さらに、ファンキーな権限も必要ありません。
MyLifecycleHandler.java:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java:
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@Mewzerはこの方法についていくつかの良い質問をしました。私はこの回答で皆に回答したいと思います。
onStop()メモリ不足の状況では呼び出されません。ここで問題ですか?
いいえ。ドキュメント onStop()言う:
onPause()メソッドが呼び出された後にアクティビティのプロセスを実行し続けるのに十分なメモリがシステムにないメモリ不足の状況では、このメソッドが呼び出されることはありません。
ここで重要なのは、「アクティビティのプロセスを実行し続ける...」です。このメモリ不足の状況に達すると、プロセスは実際に(アクティビティだけでなく)強制終了されます。つまり、a)プロセスが強制終了された場合はとにかくバックグラウンドを確認できないため、b)プロセスが再開された場合(新しいアクティビティが作成されたため)、メンバーはの変数(静的かどうか)MyLifecycleHandlerはにリセットされ0ます。
これは設定変更に有効ですか?
デフォルトではありません。マニフェストファイルに明示的にconfigChanges=orientation|screensize(|必要に応じて)設定し、構成の変更を処理する必要があります。そうしないと、アクティビティが破棄されて再作成されます。これを設定しない場合、アクティビティのメソッドは次の順序で呼び出されますonCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume。ご覧のとおり、オーバーラップはありません(通常、2つのアクティビティを切り替えると、2つのアクティビティが非常に短時間オーバーラップします。つまり、このバックグラウンド検出方法が機能します)。これを回避するにconfigChangesは、アクティビティが破壊されないように設定する必要があります。幸いなことに、私は設定する必要がありましたconfigChanges画面の回転/サイズ変更でアクティビティ全体が破壊されるのは望ましくないため、すべてのプロジェクトで既に使用されています。これが問題になることはありませんでした。(これに関する私の記憶をリフレッシュして私を訂正してくれたdpimkaに感謝します!)
1つのメモ:
この回答で「背景」と言ったのは、「アプリが表示されなくなった」という意味です。Androidアクティビティは、フォアグラウンドではなくても表示できます(たとえば、透明な通知オーバーレイがある場合)。それが私がそれを反映するためにこの回答を更新した理由です。
フォアグラウンドに何もない場所でアクティビティを切り替えると、Androidには変な気まぐれな瞬間があることを知っておくことが重要です。このため、(同じアプリ内で)アクティビティを切り替えるときにアプリがフォアグラウンドにあるかどうかを確認すると、フォアグラウンドにいないことが通知されます(アプリがまだアクティブアプリであり、表示されている場合でも) )。
後ActivityののonPause()メソッドでアプリがフォアグラウンドにあるかどうかを確認できます super.onPause()。先ほどお話した奇妙なリンボ状態を思い出してください。
の後ActivityののonStop()メソッドで、アプリが表示されているかどうか(つまり、バックグラウンドにないかどうか)を確認できます。 super.onStop()
onStop()後にバックグラウンドを確認しますsuper.onStop()。でバックグラウンドをチェックしないでくださいonPause()。
GOOGLEソリューション -以前のソリューションのようなハックではありません。ProcessLifecycleOwner Kotlinを使用します。
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
Java:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
app.gradle
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
ライフサイクル関連のアーキテクチャコンポーネントの詳細については、こちらをご覧ください-https://developer.android.com/topic/libraries/architecture/lifecycle
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }、あなたは前景の状態を取得することができますArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. 、これはmultiple processesアプリでは機能しません。エレガントに実現できるAPIはありますか?
サポートライブラリバージョン26 以降、ProcessLifecycleOwnerを使用できます。ここで説明するように、依存関係に追加するだけです。次に例を示します。
dependencies {
def lifecycle_version = "1.1.1"
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
// alternatively - Lifecycles only (no ViewModel or LiveData).
// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}
そして、ProcessLifecycleOwnerアプリの状態を知りたいときにクエリを実行します。例:
//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Android API 16以降、アプリがフォアグラウンドにあるかどうかを確認する簡単な方法があります。それは絶対確実ではないかもしれませんが、Androidのメソッドは絶対確実ではありません。このメソッドは、サービスがサーバーから更新を受信し、通知を表示するかどうかを決定する必要がある場合に十分に使用できます(UIがフォアグラウンドの場合、ユーザーは通知なしに更新に気付くため)。
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
JobServiceて、サービスがバックグラウンドで実行されていることを検出できました。
アイドロンの答えはエラーが発生しやすく、はるかに複雑ですが、ここでrepeatead はandroidアプリケーションがフォアグラウンドにあるかどうかを確認しますか?ここで、バックグラウンドタスクまたはサービスから現在のフォアグラウンドアプリケーションを特定する
より単純なアプローチがあります:
すべてのアクティビティが拡張するBaseActivityで:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
アプリケーションアクティビティのいずれかがフォアグラウンド にあるかどうかを確認する必要がある場合は、必ず確認してくださいisVisible()。
このアプローチを理解するには、アクティビティのサイドバイサイドライフサイクルの回答を確認してください:アクティビティのサイドバイサイドライフサイクル
Idolon's answer is error prone-残念ながら私はあなたに同意する必要があります。Googleグループでのダイアンハックボーンのコメントに基づいて、回答を更新しました。詳細はこちらをご確認ください。
onPause、onStop、またonResumeイベントが呼び出されます。では、これらのイベントがどれも発生しない場合はどうしますか?
Application.ActivityLifecycleCallbacksなどを使用する推奨ソリューションを試しましたが、期待どおりに動作しませんでした。Sargeのおかげで、以下で説明する非常に簡単でわかりやすいソリューションを思い付きました。
彼らは、ソリューションの重要な我々はActivityAとActivityBを、持っていると我々はActivityAからActivityBを呼び出す場合(と呼んでいないことを理解することの事実である
ActivityA.finish、そしてActivityB者)がonStart()呼び出されます前に ActivityAonStop()。
それはまたです主な違いonStop()とonPause()そのどれも私が読ん記事に言及しませんでした。
したがって、この活動のライフサイクルの挙動に基づいて、あなたは、単にやった回数を数えることができるonStart()とonPause()、あなたのプログラムで呼ばれました。カウントに使用される静的変数をインクリメント/デクリメントするには、プログラムごと ActivityにonStart()andをオーバーライドする必要があることに注意してくださいonStop()。以下は、このロジックを実装するコードです。拡張するクラスを使用しているApplicationので、Manifest.xmlApplicationタグ内で宣言することを忘れないでくださいandroid:name=".Utilities"。ただし、単純なカスタムクラスを使用して実装することもできます。
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
ここで、プログラムの各アクティビティで、次のようにオーバーライドおよびインクリメント/デクリメントする必要がonStart()ありonStop()ます。
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
このロジックでは、2つのケースが考えられます。
stateCounter = 0 :停止した数は開始したアクティビティの数と同じです。つまり、アプリケーションはバックグラウンドで実行されています。stateCounter > 0 :開始された数が停止された数よりも多いため、アプリケーションがフォアグラウンドで実行されています。通知:stateCounter < 0開始されたアクティビティではなく、停止されたアクティビティがあることを意味します。これは不可能です。このケースが発生した場合は、必要に応じてカウンターを増加または減少していないことを意味します。
あなたは行く準備ができています。アプリケーションが内のバックグラウンドにあるかどうかを確認する必要がありますonStop()。
if(Utilities.isApplicationOnBackground()) …しUtilitiesます。それ以外の場合は、特定のアクティビティのみがイベントに反応します。
あなたがそれを自分で追跡する以外に、あなたの活動のいずれかが目に見えるかどうかを判断する方法はありません。おそらく、新しいStackOverflowの質問をして、ユーザーエクスペリエンスから何を達成しようとしているのかを説明することを検討する必要があります。そうすれば、代替の実装アイデアを提供できるでしょう。
Serviceます。その場合は、アクティビティが表示されたり消えたりするときにサービスに通知します。に表示Serviceされているアクティビティがないと判断され、しばらくの間その状態が続く場合は、次の論理的な停止ポイントでデータ転送を停止します。はい、これにはアクティビティごとにコードが必要になりますが、現在のところ、それは不可避のAFAIKです。
MyActivityClass継承Activityおよび実装するクラスを作成し、すべてのアクティビティをから継承させることができますMyActivityClass。この意志のために仕事がないPreferenceActivityか、MapActivityしかし(参照この質問を)
ComponentCallbacks2を使用して、アプリがバックグラウンドにあるかどうかを検出できます。ところで、このコールバックは、APIレベル14(アイスクリームサンドイッチ)以上でのみ使用できます。
メソッドの呼び出しを取得します。
public abstract void onTrimMemory (int level)
レベルがComponentCallbacks2.TRIM_MEMORY_UI_HIDDENその場合、アプリはバックグラウンドです。
あなたはこのインタフェースを実装することができactivity、serviceなど
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// app is in background
}
}
}
@Cornstalksの回答に基づいて、いくつかの便利な機能を組み込みます。
追加機能:
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
私が思いついた最善の解決策はタイマーを使用することです。
onPause()でタイマーを開始し、onResume()で同じタイマーをキャンセルすると、Timerのインスタンスが1つあります(通常、Applicationクラスで定義されます)。タイマーが起動すると、タイマー自体が2秒後にRunnableを実行するようにタイマー自体が設定され、アプリケーションがバックグラウンドにあることを示すフラグが設定されます。
タイマーをキャンセルする前のonResume()メソッドで、バックグラウンドフラグをクエリして、起動操作(ダウンロードの開始や位置情報サービスの有効化など)を実行できます。
このソリューションでは、バックスタックにいくつかのアクティビティを設定でき、実装するための権限は必要ありません。
このソリューションは、イベントバスを使用する場合にも適切に機能します。タイマーがイベントを起動するだけで、アプリのさまざまな部分がそれに応じて応答できるためです。
開発者の設定「活動を保持しない」をオンにした場合-作成された活動の数のみを確認しても不十分です。isSaveInstanceStateも確認する必要があります。私のカスタムメソッドisApplicationRunning()チェックは、Androidアプリが実行されていることです。
ここに私の仕事のコード:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
唯一の正しい解決策:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
CommonsWareとKeyが言ったことを便乗させるために、おそらくApplicationクラスを拡張して、すべてのアクティビティでそれらをonPause / onResumeメソッドで呼び出すことができます。これにより、どのアクティビティが表示されているかを知ることができますが、おそらくより適切に処理できます。
正確に考えていることについて詳しく説明できますか?バックグラウンドで実行しているとは、現在画面に表示されていなくても、アプリケーションをメモリに保持しているだけということですか?アプリがフォーカスされていないときにアプリを管理するためのより永続的な方法として、サービスの使用を検討しましたか?
ApplicationonPause()またはがありませんonResume()。
ActivityLifecycleCallbacksを自分で実装しました。私はSherlockActivityを使用していますが、通常のActivityクラスでは機能する可能性があります。
まず、アクティビティのライフサイクルを追跡するためのすべてのメソッドを持つインターフェースを作成します。
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
次に、このインターフェイスをアプリケーションのクラスに実装しました。
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
3番目に、SherlockActivityから拡張するクラスを作成しています。
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
4番目に、SherlockActivityから拡張されたすべてのクラスをMySherlockActivityに置き換えました。
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
これで、logcatにMyApplicationで作成されたインターフェイス実装でプログラムされたログが表示されます。
まだ言及されていないため、Androidアーキテクチャコンポーネントを介して利用可能なProcessLifecycleOwnerを探索することを読者に提案します
システムは、フォアグラウンドアプリとバックグラウンドアプリを区別します。(サービス制限のためのバックグラウンドの定義は、メモリ管理で使用される定義とは異なります。アプリは、メモリ管理に関連する場合はバックグラウンドにありますが、サービスを起動する機能に関連する場合はフォアグラウンドにあります。)アプリは次のいずれかに該当する場合、フォアグラウンドにあると見なされます。
これらの条件のいずれにも該当しない場合、アプリはバックグラウンドにあると見なされます。
この古い投稿の別の解決策(役立つ可能性があるもの):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
onActivityDestroyed関数のコメントを参照してください。
SDKターゲットバージョン14で動作します>:
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
共有設定を使用してプロパティを格納し、アクティビティからのサービスバインディングを使用してプロパティを操作する必要があります。バインディングのみを使用する場合(つまり、startServiceを使用しない場合)、サービスは、それにバインドした場合にのみ実行され(onResumeをバインドし、onPauseをバインド解除して)、フォアグラウンドでのみ実行し、さらに通常のスタート/ストップサービスを使用できます。
この質問はもっと明確にすべきだと思います。いつ?どこ?アプリがバックグラウンドで動作している場合に知りたい具体的な状況は何ですか?
私は自分の方法で私のソリューションを紹介します。アプリのすべてのアクティビティのメソッドでクラスの
「重要度」フィールドを使用してこれを実現します。これは、「重要度」の値をチェックするメソッドを実装する拡張する他のアクティビティにを提供することで簡単に実現できます。これがコードです:RunningAppProcessInfoonStopBaseActivityonStop
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
このページを読むことをお勧めします:http : //developer.android.com/reference/android/app/Activity.html
つまり、onStop()が呼び出された後、アクティビティは表示されなくなります。
onStopます。between onPauseとonStopそれは可視ですが、フォアグラウンドにはありません。
onStop()呼び出された後、アクティビティは表示されなくなると私は述べました。これは、あなたが書いたものと一致しています。
onPauseと呼ばれるまで、最初に言った:最近の編集で修正されました。
私の意見では、多くの答えはコードに大きな負荷をもたらし、多くの複雑さと非可読性をもたらします。
Serviceとの間の通信方法をSOに尋ねるときActivity、私は通常LocalBroadcastManagerを使用することを勧めます。
どうして?
まあ、ドキュメントを引用して:
ブロードキャストしているデータがアプリを離れることはないので、プライベートデータの漏洩を心配する必要はありません。
他のアプリケーションがこれらのブロードキャストを自分のアプリに送信することは不可能であるため、それらが悪用できるセキュリティホールを心配する必要はありません。
システムを通じてグローバルブロードキャストを送信するよりも効率的です。
ドキュメントにはありません:
Activity、Application...説明
したがって、いずれかActivityが現在フォアグラウンドにあるかどうかを確認する必要があります。通常はService、またはApplicationクラスでそれを行います。
つまり、Activityオブジェクトは信号の送信者になります(私はオン/オフです)。あなたはService、他の一方で、なりReceiver。
フォアグラウンドとバックグラウンドのどちらであるかを通知する2つの瞬間がありますActivity(はい、2つだけです... 6ではありません)。
ときにActivityフォアグラウンドになり、onResume()この方法は(も後に呼び出さトリガされますonCreate())。
ときにActivity後ろに行く、onPause()と呼ばれています。
これらは、状態を説明Activityするために信号を送信する必要がある瞬間Serviceです。
が複数ある場合はActivity、Activity最初にがバックグラウンドに入り、次に別のものが前景に入ることに注意してください。
したがって、状況は次のようになります。*
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service/ Application単にそれらの信号のリスニングを維持し、それに応じて行動します。
コード(TLDR)
あなたがService実装しなければならないBroadcastReceiver信号をリッスンするために。
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
登録Receiver中のService::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
登録を解除する Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
今あなたActivityのは彼らの状態を伝えなければなりません。
に Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
に Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
非常に一般的な状況
開発者:自分からデータを送信し、
Serviceを更新したいActivity。Activityがフォアグラウンドにあるかどうかを確認するにはどうすればよいですか?
がActivityフォアグラウンドにあるかどうかを確認する必要は通常ありません。LocalBroadcastManagerからデータを送信するだけServiceです。Activityがオンの場合、応答して動作します。
この非常に一般的な状況では、Serviceが送信者になり、がをActivity実装しBroadcastReceiverます。
したがって、でを作成ReceiverしますActivity。に登録し、登録onResume()を解除しonPause()ます。他のライフサイクル方法を使用する必要はありません。
(ListViewの更新、これを行う、それを行う、...)でReceiver動作を定義しますonReceive()。
この方法ではActivity、フォアグラウンドにある場合にのみリッスンし、バックにある場合や破棄された場合は何も起こりません。
が複数ある場合はActivity、どちらかActivityがオンの場合に応答します(それらもを実装している場合Receiver)。
すべてがバックグラウンドにある場合、誰も応答せず、信号が失われるだけです。
信号IDを指定して、Servicevia Intent(上記のコードを参照)からデータを送信します。
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
特定のアクティビティがフォアグラウンドにあるかどうかを調べた場合、およびアプリケーションに直接アクセスできないSDKの場合、回答はどれも特定のケースに完全には適合しませんでした。私にとっては、新しいチャットメッセージのプッシュ通知を受け取ったばかりのバックグラウンドスレッドで、チャット画面がフォアグラウンドにない場合にのみシステム通知を表示したいと思っていました。
ActivityLifecycleCallbacks他の回答で推奨されているそれを使用してMyActivity、フォアグラウンドにあるかどうかのロジックを格納する小さなutilクラスを作成しました。
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
私のアクティビティでは、onResumeとonPauseを使用して、isVisibleブール値をSharedPrefencesに書き込みます。
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
必要に応じて他の場所で読んでください
// Show a Toast Notification if App is not visible (ie in background. Not running, etc)
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if(!sharedPrefs.getBoolean("visible", true)){...}
エレガントではないかもしれませんが、私にとってはうまくいきます...
答えるのは遅すぎるかもしれませんが、誰かが訪問に来た場合、私が提案する解決策は次のとおりです。アプリがバックグラウンドにある、またはフォアグラウンドに来ている状態をアプリが知りたい理由は、多数ある場合があります。ユーザーがBGにいるときにトーストと通知を表示します。2.ユーザーがBGから初めて、投票、再描画などのいくつかのタスクを実行します。
Idolonと他の人たちによる解決策は、最初の部分を処理しますが、2番目の部分は処理しません。アプリに複数のアクティビティがあり、ユーザーがそれらを切り替えている場合、2番目のアクティビティにいるときまでに、可視フラグはfalseになります。したがって、確定的に使用することはできません。
CommonsWareが提案したことを行いました。「サービスが、目に見えるアクティビティがないと判断し、しばらくの間その状態が続く場合は、次の論理的な停止ポイントでデータ転送を停止します。」
太字の行は重要であり、これを使用して2番目の項目を達成できます。つまり、onActivityPaused()を取得したら、可視を直接falseに変更せず、代わりに3秒のタイマー(次のアクティビティを起動する最大時間)を設定し、onActivityResumed( )次の3秒で呼び出し、visibleをfalseに変更します。同様にonActivityResumed()でタイマーがある場合、それをキャンセルします。つまり、visibleはisAppInBackgroundになります。
コードをコピーして貼り付けることはできません...
これを行うには別の方法を使用することをお勧めします。
プログラムの起動中に起動画面を表示する必要があると思います。すでにバックエンドで実行されている場合は、表示しないでください。
アプリケーションは現在の時刻を特定のファイルに継続的に書き込むことができます。アプリケーションの起動中に、最後のタイムスタンプを確認します。current_time-last_time>最新の時間を書き込むために指定した時間範囲の場合は、アプリケーションが停止しているか、システムまたはユーザー自身によって強制終了されています。