How to detect when an Android app goes to the background and come back to the foreground Ask Question

How to detect when an Android app goes to the background and come back to the foreground Ask Question

I am trying to write an app that does something specific when it is brought back to the foreground after some amount of time. Is there a way to detect when an app is sent to the background or brought to the foreground?

ベストアンサー1

2018: Android supports this natively through lifecycle components.

March 2018 UPDATE: There is now a better solution. See ProcessLifecycleOwner. You will need to use the new architecture components 1.1.0 (latest at this time) but it’s specifically designed to do this.

There’s a simple sample provided in this answer but I wrote a sample app and a blog post about it.

Ever since I wrote this back in 2014, different solutions arose. Some worked, some were thought to be working, but had flaws (including mine!) and we, as a community (Android) learned to live with the consequences and wrote workarounds for the special cases.

Never assume a single snippet of code is the solution you’re looking for, it’s unlikely the case; better yet, try to understand what it does and why it does it.

The MemoryBoss class was never actually used by me as written here, it was just a piece of pseudo code that happened to work.

Unless there’s valid reason for you not to use the new architecture components (and there are some, especially if you target super old apis), then go ahead and use them. They are far from perfect, but neither were ComponentCallbacks2.

UPDATE / NOTES (November 2015): People has been making two comments, first is that >= should be used instead of == because the documentation states that you shouldn't check for exact values. This is fine for most cases, but bear in mind that if you only care about doing something when the app went to the background, you will have to use == and also combine it with another solution (like Activity Lifecycle callbacks), or you may not get your desired effect. The example (and this happened to me) is that if you want to lock your app with a password screen when it goes to the background (like 1Password if you're familiar with it), you may accidentally lock your app if you run low on memory and are suddenly testing for >= TRIM_MEMORY, because Android will trigger a LOW MEMORY call and that's higher than yours. So be careful how/what you test.

Additionally, some people have asked about how to detect when you get back.

The simplest way I can think of is explained below, but since some people are unfamiliar with it, I'm adding some pseudo code right here. Assuming you have YourApplication and the MemoryBoss classes, in your class BaseActivity extends Activity (you will need to create one if you don't have one).

@Override
protected void onStart() {
    super.onStart();

    if (mApplication.wasInBackground()) {
        // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
        mApplication.setWasInBackground(false);
    }
}

ダイアログはアクティビティを一時停止できるため、全画面ダイアログを表示するだけの場合はアプリが「バックグラウンドに移動した」と認識しないようにしたいので、onStart をお勧めしますが、状況は異なる場合があります。

以上です。if ブロック内のコードは1 回だけ実行され、別のアクティビティに移動しても、新しいアクティビティ (これもextends BaseActivity) は を報告するwasInBackgroundため、が呼び出されてフラグが再び true に設定されるまでfalseコードは実行されません。onMemoryTrimmed

更新 / 注記 (2015 年 4 月) : このコードをすべてコピーして貼り付ける前に、100% の信頼性がない可能性がある例がいくつかあるため、最良の結果を得るには他の方法と組み合わせる必要があることに注意してください。特に、コールバックが実行されることが保証されていない既知の例が 2 つあります。onTrimMemory

  1. アプリが表示されている間に携帯電話の画面がロックされた場合 (デバイスが nn 分後にロックされるなど)、ロック画面が最前面にあるためこのコールバックは呼び出されません (または常に呼び出されるとは限りません)。ただし、アプリは覆われていてもまだ「実行中」です。

  2. デバイスのメモリが比較的少ない場合 (およびメモリに負荷がかかっている場合)、オペレーティング システムはこの呼び出しを無視し、より重大なレベルに直接進むようです。

ここで、アプリがいつバックグラウンドに移動したかを知ることがどれほど重要かに応じて、アクティビティのライフサイクルなどを追跡しながらこのソリューションを拡張する必要がある場合と、そうでない場合があります。

上記の点を念頭に置いて、優れた QA チームを構築してください ;)

更新終了

遅いかもしれませんが、 Ice Cream Sandwich (API 14) および Above には信頼できる方法があります。

アプリに表示可能なUIがなくなると、コールバックがトリガーされます。カスタムクラスで実装できるコールバックは、コンポーネントコールバック2(はい、2 です)。このコールバックは、API レベル 14 (Ice Cream Sandwich) 以上でのみ使用できます。

基本的には、次のメソッドを呼び出します。

public abstract void onTrimMemory (int level)

レベルは20以上です

public static final int TRIM_MEMORY_UI_HIDDEN

私はこれをテストしてきましたが、常に機能します。レベル 20 は、アプリが表示されなくなったため、一部のリソースを解放する必要があるかもしれないという「提案」にすぎないためです。

公式ドキュメントを引用すると:

onTrimMemory(int) のレベル: プロセスはユーザー インターフェイスを表示していましたが、現在は表示していません。メモリをより適切に管理できるように、この時点で UI による大きな割り当てを解放する必要があります。

もちろん、実際に指示どおりの動作を行うには、これを実装する必要があります (一定時間使用されていないメモリを消去する、使用されていないコレクションをクリアするなど)。可能​​性は無限です (その他のより重要なレベルについては、公式ドキュメントを参照してください)。

しかし、興味深いのは、OS が「アプリがバックグラウンドに移動しました」と通知していることです。

それはまさにあなたが最初に知りたかったことです。

いつ戻ってきたかどうやって判断するんですか?

まあ、それは簡単です。きっと「BaseActivity」があるので、 onResume() を使用して、戻ってきたことをフラグ付けできます。戻っていないと通知されるのは、上記のメソッドの呼び出しを実際に受け取ったときだけだからですonTrimMemory

うまくいきます。誤検知はありません。アクティビティが再開している場合は、100% の確率で戻っています。ユーザーが再び戻ると、別のonTrimMemory()呼び出しが行われます。

アクティビティ (または、カスタム クラス) をサブスクライブする必要があります。

常にこれを受け取ることを保証する最も簡単な方法は、次のような単純なクラスを作成することです。

public class MemoryBoss 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) {
            // We're in the Background
        }
        // you might as well implement some memory cleanup here and be a nice Android dev.
    }
}

これを使用するには、アプリケーションの実装 (すでに実装されていますよね? ) で、次のようにします。

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

を作成すると、それに をInterface追加して、 API 14 未満で使用されるを実装できます (2 なし)。そのコールバックにはメソッドのみがあり、バックグラウンドに移動したときには呼び出されませんが、メモリを削減するために使用する必要があります。elseifComponentCallbacksonLowMemory()

次に、アプリを起動してホームを押します。onTrimMemory(final int level)メソッドが呼び出されるはずです (ヒント: ログを追加します)。

最後のステップは、コールバックから登録を解除することです。おそらく最適な場所はonTerminate()アプリのメソッドです、そのメソッドは実際のデバイスでは呼び出されません。

/**
 * This method is for use in emulated process environments.  It will
 * never be called on a production Android device, where processes are
 * removed by simply killing them; no user code (including this callback)
 * is executed when doing so.
 */

したがって、本当に登録されたくない状況でない限り、プロセスは OS レベルで終了するため、安全に無視できます。

ある時点で登録を解除することにした場合 (たとえば、アプリがクリーンアップして終了するためのシャットダウン メカニズムを提供する場合)、次の操作を実行できます。

unregisterComponentCallbacks(mMemoryBoss);

以上です。

おすすめ記事