Androidアプリケーションがバックグラウンドで実行されているかどうかの確認


329

バックグラウンドで言うと、アプリケーションのアクティビティは現在、ユーザーには表示されていません。



7
私はここで混乱しています。なぜ、これのためにアプリケーションクラスの単純なオーバーライドをandroidが提供できないのですか?これをプラットフォームレベルで知るのは難しいですか。@Override protected void onApplicationSentToBackground(){}
チャックD

2
@ChuckD-これは理にかなっています。これは、Android SDKが時々回避することを好むようです。:/
マーク


1
iOSはこれを踏襲しているが、なぜGoogleがこれをそんなに難しくしているのかわからない。それはそのような明らかな必要性です。
Jerry Destremps

回答:


388

アプリケーションがバックグラウンドで実行されているかどうかを検出する方法はいくつかありますが、完全に信頼できるのはそのうちの1つだけです。

  1. 適切なソリューション(クレジットに行くダンCommonsWareNeTeInStEiN
    使用して自分で自分のアプリケーションのトラックの可視性Activity.onPauseActivity.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の回答を確認してください。


  2. 次の解決策を提案するために私が使用した間違ったもの

    レコードのActivityManager.getRunningAppProcesses()リストを返す現在のフォアグラウンド/バックグラウンドアプリケーションを検出できますRunningAppProcessInfo。アプリケーションがフォアグラウンドチェックRunningAppProcessInfo.importanceフィールドにあるかどうかを確認するには、RunningAppProcessInfo.IMPORTANCE_FOREGROUNDwhile RunningAppProcessInfo.processNameがアプリケーションパッケージ名と等しいかどうかを確認します。

    またActivityManager.getRunningAppProcesses()、アプリケーションUIスレッドから呼び出すと、IMPORTANCE_FOREGROUND実際にフォアグラウンドにあるかどうかに関係なく、タスクの重要性が返されます。バックグラウンドスレッドで(たとえばを介してAsyncTask)呼び出すと、正しい結果が返されます。

    このソリューションは機能する可能性があります(実際、ほとんどの場合機能します)が、使用は控えることを強くお勧めします。そして、これが理由です。ダイアン・ハックボーンが書いたように

    これらのAPIは、アプリケーションがUIフローのベースにするためのものではなく、実行中のアプリやタスクマネージャーなどをユーザーに表示するためのものです。

    はい、これらのためにメモリに保持されているリストがあります。ただし、別のプロセスではオフであり、別のプロセスで管理されており、スレッドとは別のスレッドで実行されているため、(a)正しい判断を下すために時間内に確認したり、(b)戻ってくるまでに一貫した状況を把握したりできません。さらに、「次の」アクティビティに何をするかについての決定は、切り替えが発生するポイントで常に行われ、その正確なポイント(アクティビティ状態が切り替えを行うために短時間ロックダウンされる)までは行われません。実際に次のことがどうなるかを確実に知っています。

    ここでの実装とグローバルな動作は、将来同じであるとは限りません。

    私がSOに回答を投稿する前にこれを読んでいたらいいのですが、うまくいけば、私のエラーを認めるには遅すぎません。

  3. 回答の1つで言及されている別の間違ったソリューション
    Droid-FuライブラリはActivityManager.getRunningTasks、そのisApplicationBroughtToBackground方法に使用しています。上記のダイアンのコメントを参照してください。その方法も使用しないでください。


4
ホームボタンを押したかどうか、または他のアプリがフォーカスを取得したかどうかを確認するには:1)を実装します 適切なソリューションをます。2)OnStopへの要請に応じてisActivityVisible
Brais Gabin、2012年

28
残念ながら、あなたの「正しい」解決策は私にはうまくいきません。アプリ内のアクティビティを循環することを検討してください。その場合、「inForeground」フラグは次のようになります。True、False(最初のアクティビティのonPauseと2番目のアクティビティのonResumeの間)、次にTrueなど。その後、何らかのヒステリシスが必要になります。
ラドゥ

14
すべてのアクティビティを直接制御できない場合、このソリューションは機能しません。たとえば、サードパーティのSDKからのアクティビティがある場合、またはACTION_VIEWインテントを起動する場合さえあります。
user123321 2013年

66
Androidはとてもおかしな問題です。誰かがアプリレベルのデータを永続化したいと思う人はいないでしょうか?休憩してください

8
この質問に対する本当の答えは「あなたはそれを適切にチェックすることができない」であるように見えます。いわゆる「正しい」ソリューションはせいぜい回避策なので、ActivityLifecycleCallbacksを使用しています。「フォアグラウンドではない」として登録されるアクティビティ間の切り替えを検討する必要があります。こんな簡単なことはチェックできないと思う…
セリーヌ

263

この回答は使用しないでください

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()


1
これは興味深いように見えますが、メモリ不足の状況ではどうなりますか?onStop()が呼び出されることは保証されていません。onStop()が呼び出されず、停止されたカウンターがインクリメントされない状況になる可能性はありますか?これは、バックグラウンドチェックが信頼できないことを意味しますか?それともこれは決して起こりませんか?
Mewzer

1
また、これは構成の変更を無視しますか?または、構成の変更(方向の変更など)の結果としてアクティビティが再作成された場合、アプリケーションはバックグラウンドと見なされますか?申し訳ありませんが、質問についてですが、あなたは何かに興味があり、これらのエッジケースで機能するかどうかを知りたいと思っています。
Mewzer

1
@Mewzer:私はコメントとして応答するつもりでしたが、これらの回答を得るには少しタイプする必要があるので、数分後にもう一度確認して、私の回答を編集します。
Cornstalks

1
@Mewzer:あなたは今あなたの答えを見つけるべきです。他にご不明な点がありましたらお知らせください。
Cornstalks

2
@Mewzer:興味があるかもしれないというメモを追加しました。具体的には、onStop()後にバックグラウンドを確認しますsuper.onStop()。でバックグラウンドをチェックしないでくださいonPause()
Cornstalks

187

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


10
これは間違いなく正しい答えです。それは魅力のように機能しました:D
JaviOverflow

2
:これは私が外にこのクラスより簡単にフォアグラウンド/バックグラウンド状態にアクセスできるように、私も少し変更され、完璧に動作しcompanion object { private var foreground = false fun isForeground() : Boolean { return foreground } }、あなたは前景の状態を取得することができますArchLifecycleApp.isForeground()
ホセ・ジェット

2
ああ、これは私の古い答えよりもはるかに優れています。私から+1してください。私はあなたの答えを人々に示すように私の答えを更新しました。
Cornstalks

2
これは正解ですが、コールバックを実装する必要はありませんが、いつでもProcessLifecycleOwnerにクエリを実行できます。stackoverflow.com/a/52678290/6600000を
Keivan Esbati 2018年

2
docが言うように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はありますか?
acntwww

23

サポートライブラリバージョン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);

2
おかげで、これはfcmを使用するときにコードのどの部分にも特に適した、最も簡単な方法です。
ミハエキール

アプリケーションが完全に閉じられた場合、最初のメソッドは何を返しますか?
Evgeniy Mishustin

@EvgeniyMishustinはアプリケーションの現在の状態に依存しますが、通常はCREATEDの後にDESTROYEDが表示され、その後は新しいイベントを受け取りません。
ケイバンエスバティ

したがって、IFアプリがバックグラウンド(フォアグラウンド)にあることを確認するための「IF」ステートメントはどこにありますか?
ekashking

@ekashkingはステートメント全体をif節に入れるだけです。例:if(ProcessLifecycleOwner.get()。getLifecycle()。getCurrentState()。isAtLeast(Lifecycle.State.STARTED))=>アプリがフォアグラウンドにある
Keivan Esbati

20

Android API 16以降、アプリがフォアグラウンドにあるかどうかを確認する簡単な方法があります。それは絶対確実ではないかもしれませんが、Androidのメソッドは絶対確実ではありません。このメソッドは、サービスがサーバーから更新を受信し、通知を表示するかどうかを決定する必要がある場合に十分に使用できます(UIがフォアグラウンドの場合、ユーザーは通知なしに更新に気付くため)。

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

このコードは、Serviceクラスまたは他のクラス(アプリケーションクラスなど)内にある必要がありますか?どうもありがとう。
Woppi

..最後の行としてそれを使用したいところはどこでも、チェックするブール値です。
AO_ 2017年

これは、プッシュ通知用のAWS Android SDKと同じ方法です。
spakmad 2017年

「サービス制限のためのバックグラウンドの定義は、メモリ管理で使用される定義とは異なります。アプリは、メモリ管理に関連する場合はバックグラウンドにありますが、サービスを起動する機能に関連する場合はフォアグラウンドにある場合があります。) 「developer.android.com/about/versions/oreo/background.html
ARLabs

ありがとう、これでうまくいきました!このコードをで使用しJobServiceて、サービスがバックグラウンドで実行されていることを検出できました。
Michael Osofsky

17

アイドロンの答えはエラーが発生しやすく、はるかに複雑ですが、ここで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()

このアプローチを理解するには、アクティビティのサイドバイサイドライフサイクルの回答を確認してください:アクティビティのサイドバイサイドライフサイクル


3
Idolon's answer is error prone-残念ながら私はあなたに同意する必要があります。Googleグループでのダイアンハックボーンのコメントに基づいて、回答を更新しました。詳細はこちらをご確認ください。
Idolon

2
これも間違いのない解決策ではありません。1つのシナリオは、ユーザーが、通知パネルを引き下げている場合ではありませんどちらもonPauseonStop、またonResumeイベントが呼び出されます。では、これらのイベントがどれも発生しない場合はどうしますか?

これは、この質問に私を導いた:stackoverflow.com/questions/33657102/...
Ruchir Baronia

残念ながら、画面がオフのときにアクティビティが開始されると、このコードは正しく機能しません。この場合、onResumeとonPauseが呼び出され、isVisible = falseになります。
CoolMind 2016年

@CoolMindバックグラウンドでアクティビティを起動するユースケースは何ですか?
ネタインシュタイン2016年

11

Application.ActivityLifecycleCallbacksなどを使用する推奨ソリューションを試しましたが、期待どおりに動作しませんでした。Sargeのおかげで、以下で説明する非常に簡単でわかりやすいソリューションを思い付きました。

彼らは、ソリューションの重要な我々はActivityAとActivityBを、持っていると我々はActivityAからActivityBを呼び出す場合(と呼んでいないことを理解することの事実であるActivityA.finish、そしてActivityB者)がonStart()呼び出されます前に ActivityA onStop()

それはまたです主な違いonStop()onPause()そのどれも私が読ん記事に言及しませんでした。

したがって、この活動のライフサイクルの挙動に基づいて、あなたは、単にやった回数を数えることができるonStart()onPause()、あなたのプログラムで呼ばれました。カウントに使用される静的変数をインクリメント/デクリメントするには、プログラムごと ActivityonStart()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つのケースが考えられます。

  1. stateCounter = 0 :停止した数は開始したアクティビティの数と同じです。つまり、アプリケーションはバックグラウンドで実行されています。
  2. stateCounter > 0 :開始された数が停止された数よりも多いため、アプリケーションがフォアグラウンドで実行されています。

通知:stateCounter < 0開始されたアクティビティではなく、停止されたアクティビティがあることを意味します。これは不可能です。このケースが発生した場合は、必要に応じてカウンターを増加または減少していないことを意味します。

あなたは行く準備ができています。アプリケーションが内のバックグラウンドにあるかどうかを確認する必要がありますonStop()


に移動if(Utilities.isApplicationOnBackground()) …Utilitiesます。それ以外の場合は、特定のアクティビティのみがイベントに反応します。
表示名

10

あなたがそれを自分で追跡する以外に、あなたの活動のいずれかが目に見えるかどうかを判断する方法はありません。おそらく、新しいStackOverflowの質問をして、ユーザーエクスペリエンスから何を達成しようとしているのかを説明することを検討する必要があります。そうすれば、代替の実装アイデアを提供できるでしょう。


2
Androidでは、「バックグラウンドデータ」という設定があります。この設定は、アプリケーションがバックグラウンドで実行されているときに、バックグラウンドデータ接続をオフにします。アプリケーションに「バックグラウンドデータ」トグルを実装したいので、ユーザーにアクティビティが表示されない場合は、サービスにデータ転送を停止させたいのですが、アクティビティの1つが再開した瞬間に、データ転送の再開
cppdev

1
@cppdev:うまくいけば、「データ転送」はによって行われていServiceます。その場合は、アクティビティが表示されたり消えたりするときにサービスに通知します。に表示Serviceされているアクティビティがないと判断され、しばらくの間その状態が続く場合は、次の論理的な停止ポイントでデータ転送を停止します。はい、これにはアクティビティごとにコードが必要になりますが、現在のところ、それは不可避のAFAIKです。
CommonsWare、2009

1
すべてのアクティビティ間で共通のコードをコピーして貼り付けたくない場合は、ライフサイクルメソッドをMyActivityClass継承Activityおよび実装するクラスを作成し、すべてのアクティビティをから継承させることができますMyActivityClass。この意志のために仕事がないPreferenceActivityか、MapActivityしかし(参照この質問を
ギヨームBrunerie

@CommonsWare私はOnPause()OnResume()でアクティブかどうかを試しましたが、バックグラウンドで実行している場合、アプリがビュー画面に表示されない場合、アクティブかどうかを確認します
Manoj

@CommonsWare私はOnPause()OnResume()でアクティブかどうかを試しましたが、バックグラウンドで実行している場合、アプリがビュー画面に表示されない場合、アクティブかどうかを確認します
Manoj

5

ComponentCallbacks2を使用して、アプリがバックグラウンドにあるかどうかを検出できます。ところで、このコールバックは、APIレベル14(アイスクリームサンドイッチ)以上でのみ使用できます

メソッドの呼び出しを取得します。

public abstract void onTrimMemory (int level)

レベルがComponentCallbacks2.TRIM_MEMORY_UI_HIDDENその場合、アプリはバックグラウンドです。

あなたはこのインタフェースを実装することができactivityserviceなど

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
     }
   }
}

1
あなたの答えを試しましたが、それほど信頼できません。画面がロックされている場合、または「電源」ボタンを押して画面をロックしている場合、onTrimMemoryコールバックはトリガーされません。また、アプリが表示されていて、ステータスバーの通知を介して別のアプリを開いた場合も、常にTRIM_MEMORY_UI_HIDDENが返されるわけではありません。信頼できる唯一のソリューションは、ActivityLifecycleCallbacksを実装して、ユースケースに合わせて調整することです。
velval

4

@Cornstalksの回答に基づいて、いくつかの便利な機能を組み込みます。

追加機能:

  • シングルトンパターンが導入されたため、アプリケーションのどこでもこれを実行できます:AppLifecycleHandler.isApplicationVisible()およびAppLifecycleHandler.isApplicationInForeground()
  • 重複イベントの処理を追加しました(コメント//可視性の変更時に何らかのアクションを実行し、//フォアグラウンドでの変更時に何らかのアクションを実行)

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;
    }
}

3

私が思いついた最善の解決策はタイマーを使用することです。

onPause()でタイマーを開始し、onResume()で同じタイマーをキャンセルすると、Timerのインスタンスが1つあります(通常、Applicationクラスで定義されます)。タイマーが起動すると、タイマー自体が2秒後にRunnableを実行するようにタイマー自体が設定され、アプリケーションがバックグラウンドにあることを示すフラグが設定されます。

タイマーをキャンセルする前のonResume()メソッドで、バックグラウンドフラグをクエリして、起動操作(ダウンロードの開始や位置情報サービスの有効化など)を実行できます。

このソリューションでは、バックスタックにいくつかのアクティビティを設定でき、実装するための権限は必要ありません。

このソリューションは、イベントバスを使用する場合にも適切に機能します。タイマーがイベントを起動するだけで、アプリのさまざまな部分がそれに応じて応答できるためです。


私はこれが最良の(残念ながら)解決策であると考え始めています
dhaag23

はい、これは私が管理した中でも最高のソリューションです。アプリがフォアグラウンドになっていないときにBluetoothスキャンを停止する必要がありましたが、ユーザーがアプリ内を移動したときに常に停止して開始したくなかったため、onpauseやstopまたはdestroyを使用できませんでした。
CaptRespect 2016

3

開発者の設定「活動を保持しない」をオンにした場合-作成された活動の数のみを確認しても不十分です。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) { }        

}

3

唯一の正しい解決策:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java:

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) {
            ...
        }
    }

}

このソリューションで、アプリがバックグラウンドとフォアグラウンドのどちらにあるかに関わらず、アクティビティ(またはフラグメント)のIFステートメント内の簡単な質問にどのように答えられるかわかりません。「IF」ステートメントはどこにありますか???
ekashking

2

CommonsWareとKeyが言ったことを便乗させるために、おそらくApplicationクラスを拡張して、すべてのアクティビティでそれらをonPause / onResumeメソッドで呼び出すことができます。これにより、どのアクティビティが表示されているかを知ることができますが、おそらくより適切に処理できます。

正確に考えていることについて詳しく説明できますか?バックグラウンドで実行しているとは、現在画面に表示されていなくても、アプリケーションをメモリに保持しているだけということですか?アプリがフォーカスされていないときにアプリを管理するためのより永続的な方法として、サービスの使用を検討しましたか?


Androidでは、「バックグラウンドデータ」という設定があります。この設定は、アプリケーションがバックグラウンドで実行されているときに、バックグラウンドデータ接続をオフにします。アプリケーションに「バックグラウンドデータ」トグルを実装したいので、ユーザーにアクティビティが表示されない場合は、サービスにデータ転送を停止させたいのですが、アクティビティの1つが再開した瞬間に、データ転送を再開する
cppdev

1
ApplicationonPause()またはがありませんonResume()
CommonsWare、2009

1
@CommonsWareそのとおりです。一時停止/再開時にアプリケーションにアクセスする個々のアクティビティを参照していました。これは基本的に、あなたが回答へのコメントで共有したアイデアですが、私が想像するより賢明な動きであるサービスを使用しました。
Dan

2

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で作成されたインターフェイス実装でプログラムされたログが表示されます。


1

ダイアログがダイアログの上に来るとアクティビティが一時停止するため、推奨されるソリューションはすべてハーフソリューションです。ダイアログのフックも作成する必要があります。



1

公式ドキュメント:

システムは、フォアグラウンドアプリとバックグラウンドアプリを区別します。(サービス制限のためのバックグラウンドの定義は、メモリ管理で使用される定義とは異なります。アプリは、メモリ管理に関連する場合はバックグラウンドにありますが、サービスを起動する機能に関連する場合はフォアグラウンドにあります。)アプリは次のいずれかに該当する場合、フォアグラウンドにあると見なされます。

  1. アクティビティが開始されているか一時停止されているかに関係なく、アクティビティが表示されます。
  2. フォアグラウンドサービスがあります。
  3. 別のフォアグラウンドアプリは、そのサービスの1つにバインドするか、そのコンテンツプロバイダーの1つを利用することによって、アプリに接続されます。たとえば、別のアプリが次のアプリにバインドしている場合、アプリはフォアグラウンドにあります。
    • IME
    • 壁紙サービス
    • 通知リスナー
    • 音声またはテキストサービス

これらの条件のいずれにも該当しない場合、アプリはバックグラウンドにあると見なされます。


0

この古い投稿の別の解決策(役立つ可能性があるもの):


<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();
    }

}

0

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++;
    }
}

0

共有設定を使用してプロパティを格納し、アクティビティからのサービスバインディングを使用してプロパティを操作する必要があります。バインディングのみを使用する場合(つまり、startServiceを使用しない場合)、サービスは、それにバインドした場合にのみ実行され(onResumeをバインドし、onPauseをバインド解除して)、フォアグラウンドでのみ実行し、さらに通常のスタート/ストップサービスを使用できます。


0

この質問はもっと明確にすべきだと思います。いつ?どこ?アプリがバックグラウンドで動作している場合に知りたい具体的な状況は何ですか?

私は自分の方法で私のソリューションを紹介します。アプリのすべてのアクティビティのメソッドでクラスの
「重要度」フィールドを使用してこれを実現します。これは、「重要度」の値をチェックするメソッドを実装する拡張する他のアクティビティにを提供することで簡単に実現できます。これがコードです: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;
}

@アイドルの回答で述べられているように、これは推奨されるソリューションではありません。
CoolMind 2016年

0

このページを読むことをお勧めします:http : //developer.android.com/reference/android/app/Activity.html

つまり、onStop()が呼び出された後、アクティビティは表示されなくなります。


3
アプリケーションには約10のアクティビティがあります。したがって、ユーザーに表示されている場合、それらのどれもないかどうかを知りたいです。全体として、アプリケーション全体がバックグラウンドで実行されているかどうかを知りたい
cppdev

したがって、10種類すべてを追跡します。または、CommonsWareが提案したように、何をしようとしているのか説明してください。
Key

3
これは正しくありません。アクティビティはまで表示されonStopます。between onPauseonStopそれは可視ですが、フォアグラウンドにはありません。
ニックグリム2015年

@nickgrim:何が正しくないのですか?onStop()呼び出された後、アクティビティは表示されなくなると私は述べました。これは、あなたが書いたものと一致しています。
キー

@Key:onPauseと呼ばれるまで、最初に言った:最近の編集で修正されました。
Nickgrim


0

私の意見では、多くの答えはコードに大きな負荷をもたらし、多くの複雑さと非可読性をもたらします。

Serviceとの間の通信方法をSOに尋ねるときActivity、私は通常LocalBroadcastManagerを使用することを勧めます。


どうして?

まあ、ドキュメントを引用して:

  • ブロードキャストしているデータがアプリを離れることはないので、プライベートデータの漏洩を心配する必要はありません。

  • 他のアプリケーションがこれらのブロードキャストを自分のアプリに送信することは不可能であるため、それらが悪用できるセキュリティホールを心配する必要はありません。

  • システムを通じてグローバルブロードキャストを送信するよりも効率的です。

ドキュメントにはありません:

  • 外部ライブラリは必要ありません
  • コードは最小限です
  • 実装して理解するのが速い
  • カスタムの自己実装のコールバックはありません/超シングルトン/プロセス内パターンはまったくありません...
  • ノー強い参照ActivityApplication...

説明

したがって、いずれかActivityが現在フォアグラウンドにあるかどうかを確認する必要があります。通常はService、またはApplicationクラスでそれを行います。

つまり、Activityオブジェクトは信号の送信者になります(私はオン/オフです)。あなたはService、他の一方で、なりReceiver

フォアグラウンドとバックグラウンドのどちらであるかを通知する2つの瞬間がありますActivity(はい、2つだけです... 6ではありません)。

ときにActivityフォアグラウンドになり、onResume()この方法は(も後に呼び出さトリガされますonCreate())。

ときにActivity後ろに行く、onPause()と呼ばれています。

これらは、状態を説明Activityするために信号を送信する必要がある瞬間Serviceです。

が複数ある場合はActivityActivity最初にがバックグラウンドに入り、次に別のものが前景に入ることに注意してください。

したがって、状況は次のようになります。*

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を更新したいActivityActivityがフォアグラウンドにあるかどうかを確認するにはどうすればよいですか?

Activityフォアグラウンドにあるかどうかを確認する必要は通常ありません。LocalBroadcastManagerからデータを送信するだけServiceです。Activityがオンの場合、応答して動作します。

この非常に一般的な状況では、Serviceが送信者になり、がをActivity実装しBroadcastReceiverます。

したがって、でを作成ReceiverしますActivity。に登録し、登録onResume()を解除しonPause()ます。他のライフサイクル方法を使用する必要はありません

(ListViewの更新、これを行う、それを行う、...)でReceiver動作を定義しますonReceive()

この方法ではActivity、フォアグラウンドにある場合にのみリッスンし、バックにある場合や破棄された場合は何も起こりません。

が複数ある場合はActivity、どちらかActivityがオンの場合に応答します(それらもを実装している場合Receiver)。

すべてがバックグラウンドにある場合、誰も応答せず、信号が失われるだけです。

信号IDを指定して、Servicevia Intent(上記のコードを参照)からデータを送信します。



0
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
}

0

特定のアクティビティがフォアグラウンドにあるかどうかを調べた場合、およびアプリケーションに直接アクセスできない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
    }
}

}


-1

私のアクティビティでは、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)){...}

エレガントではないかもしれませんが、私にとってはうまくいきます...


-1

答えるのは遅すぎるかもしれませんが、誰かが訪問に来た場合、私が提案する解決策は次のとおりです。アプリがバックグラウンドにある、またはフォアグラウンドに来ている状態をアプリが知りたい理由は、多数ある場合があります。ユーザーがBGにいるときにトーストと通知を表示します。2.ユーザーがBGから初めて、投票、再描画などのいくつかのタスクを実行します。

Idolonと他の人たちによる解決策は、最初の部分を処理しますが、2番目の部分は処理しません。アプリに複数のアクティビティがあり、ユーザーがそれらを切り替えている場合、2番目のアクティビティにいるときまでに、可視フラグはfalseになります。したがって、確定的に使用することはできません。

CommonsWareが提案したことを行いました。「サービスが、目に見えるアクティビティがないと判断し、しばらくの間その状態が続く場合は、次の論理的な停止ポイントでデータ転送を停止します。」

太字の行は重要であり、これを使用して2番目の項目を達成できます。つまり、onActivityPaused()を取得したら、可視を直接falseに変更せず、代わりに3秒のタイマー(次のアクティビティを起動する最大時間)を設定し、onActivityResumed( )次の3秒で呼び出し、visibleをfalseに変更します。同様にonActivityResumed()でタイマーがある場合、それをキャンセルします。つまり、visibleはisAppInBackgroundになります。

コードをコピーして貼り付けることはできません...


-3

これを行うには別の方法を使用することをお勧めします。

プログラムの起動中に起動画面を表示する必要があると思います。すでにバックエンドで実行されている場合は、表示しないでください。

アプリケーションは現在の時刻を特定のファイルに継続的に書き込むことができます。アプリケーションの起動中に、最後のタイムスタンプを確認します。current_time-last_time>最新の時間を書き込むために指定した時間範囲の場合は、アプリケーションが停止しているか、システムまたはユーザー自身によって強制終了されています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.