Checking if an Android application is running in the background

前端 未结 30 2795
无人共我
无人共我 2020-11-21 06:19

By background, I mean none of the application\'s activities are currently visible to the user?

30条回答
  •  说谎
    说谎 (楼主)
    2020-11-21 07:14

    In my opinion, many answers introduce a heavy load of code and bring lots of complexity and non-readability.

    When people ask on SO how to communicate between a Service and a Activity, I usually advice to use the LocalBroadcastManager.


    Why?

    Well, by quoting the docs:

    • You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.

    • It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.

    • It is more efficient than sending a global broadcast through the system.

    Not in the the docs:

    • It does not require external libraries
    • The code is minimal
    • It's fast to implement and understand
    • No custom self-implemented callbacks / ultra-singleton / intra-process pattern whatsoever...
    • No strong references on Activity, Application, ...

    Description

    So, you want to check if any of the Activity is currently in the foreground. You usually do that in a Service, or your Application class.

    This means, your Activity objects become the sender of a signal (I'm on / I'm off). Your Service, on the other hand, becomes the Receiver.

    There are two moments in which your Activity tells you if it's going in the foreground or in the background (yes only two... not 6).

    When the Activity goes into the foreground, the onResume() method is triggered (also called after onCreate()).

    When the Activity goes in the back, onPause() is called.

    These are the moments in which your Activity should send the signal to your Service to describe its state.

    In case of multiple Activity's, remember the an Activity goes into the background first, then another one comes into the foreground.

    So the situation would be:*

    Activity1 -- send --> Signal:OFF
    Activity2 -- send --> Signal:ON
    

    The Service / Application will simply keep listening for those signals and act accordingly.


    Code (TLDR)

    Your Service must implement a BroadcastReceiver in order to listen for signals.

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

    Register the Receiver in Service::onCreate()

    @Override
    protected void onCreate() {
        LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
    }
    

    Un-register it in Service::onDestroy()

    @Override
    protected void onDestroy() {
        // I'm dead, no need to listen to anything anymore.
        LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
    }
    

    Now your Activity's must communicated their state.

    In Activity::onResume()

    Intent intent = new Intent();
    intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
    LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
    

    In Activity::onPause()

    Intent intent = new Intent();
    intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
    LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
    

    A very, very common situation

    Developer: I want to send data from my Service and update the Activity. How do I check if the Activity is in the foreground?

    There is usually no need to check if the Activity is in the foreground or not. Just send the data via LocalBroadcastManager from your Service. If the Activity is on, then it will respond and act.

    For this very common situation, the Service becomes the sender, and the Activity implements the BroadcastReceiver.

    So, create a Receiver in your Activity. Register it in onResume() and un-register it in onPause(). There is no need to use the other life-cycle methods.

    Define the Receiver behavior in onReceive() (update ListView, do this, do that, ...).

    This way the Activity will listen only if it's in the foreground and nothing will happen if it's in the back or is destroyed.

    In case of multiple Activity's, whichever Activity is on will respond (if they also implement the Receiver).

    If all are in the background, nobody will respond and the signal will simply get lost.

    Send the data from the Service via Intent (see code above) by specifying the signal ID.


    • Except for Multi-Window Support. It may be tricky (please test it if needed)...

提交回复
热议问题