Checking if an Android application is running in the background

前端 未结 30 2841
无人共我
无人共我 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:06
    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 讨论(0)
  • 2020-11-21 07:08

    Since Android API 16 there is a simple way to check if app is in foreground. It may not be foolproof, but no methods on Android are foolproof. This method is good enough to use when your service receives update from server and has to decide whether to show notification, or not (because if UI is foreground, user will notice the update without notification).

    RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(myProcess);
    isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
    
    0 讨论(0)
  • 2020-11-21 07:08

    I think this question should be more clear. When? Where? What is your specific situation you want to konw if your app is in background?

    I just introduce my solution in my way.
    I get this done by using the field "importance" of RunningAppProcessInfo class in every activity's onStop method in my app, which can be simply achieved by providing a BaseActivity for other activities to extend which implements the onStop method to check the value of "importance". Here is the code:

    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;
    }
    
    0 讨论(0)
  • 2020-11-21 07:09

    There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:

    1. The right solution (credits go to Dan, CommonsWare and NeTeInStEiN)
      Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class. Good choices are your own implementation of the Application or a Service (there are also a few variations of this solution if you'd like to check activity visibility from the service).
       
      Example
      Implement custom Application class (note the isActivityVisible() static method):

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

      Register your application class in AndroidManifest.xml:

      <application
          android:name="your.app.package.MyApplication"
          android:icon="@drawable/icon"
          android:label="@string/app_name" >
      

      Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):

      @Override
      protected void onResume() {
        super.onResume();
        MyApplication.activityResumed();
      }
      
      @Override
      protected void onPause() {
        super.onPause();
        MyApplication.activityPaused();
      }
      

       
      Update
      ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.

    2. The wrong one
      I used to suggest the following solution:

      You can detect currently foreground/background application with ActivityManager.getRunningAppProcesses() which returns a list of RunningAppProcessInfo records. To determine if your application is on the foreground check RunningAppProcessInfo.importance field for equality to RunningAppProcessInfo.IMPORTANCE_FOREGROUND while RunningAppProcessInfo.processName is equal to your application package name.

      Also if you call ActivityManager.getRunningAppProcesses() from your application UI thread it will return importance IMPORTANCE_FOREGROUND for your task no matter whether it is actually in the foreground or not. Call it in the background thread (for example via AsyncTask) and it will return correct results.

      While this solution may work (and it indeed works most of the time) I strongly recommend to refrain from using it. And here's why. As Dianne Hackborn wrote:

      These APIs are not there for applications to base their UI flow on, but to do things like show the user the running apps, or a task manager, or such.

      Yes there is a list kept in memory for these things. However, it is off in another process, managed by threads running separately from yours, and not something you can count on (a) seeing in time to make the correct decision or (b) have a consistent picture by the time you return. Plus the decision about what the "next" activity to go to is always done at the point where the switch is to happen, and it is not until that exact point (where the activity state is briefly locked down to do the switch) that we actually know for sure what the next thing will be.

      And the implementation and global behavior here is not guaranteed to remain the same in the future.

      I wish I had read this before I posted an answer on the SO, but hopefully it's not too late to admit my error.

    3. Another wrong solution
      Droid-Fu library mentioned in one of the answers uses ActivityManager.getRunningTasks for its isApplicationBroughtToBackground method. See Dianne's comment above and don't use that method either.

    0 讨论(0)
  • 2020-11-21 07:10

    GOOGLE SOLUTION - not a hack, like previous solutions. Use 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
        }
    }
    

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

    You can read more about Lifecycle related architecture components here - https://developer.android.com/topic/libraries/architecture/lifecycle

    0 讨论(0)
  • 2020-11-21 07:11

    The best solution I have come up with uses timers.

    You have start a timer in onPause() and cancel the same timer in onResume(), there is 1 instance of the Timer (usually defined in the Application class). The timer itself is set to run a Runnable after 2 seconds (or whatever interval you think is appropriate), when the timer fires you set a flag marking the application as being in the background.

    In the onResume() method before you cancel the timer, you can query the background flag to perform any startup operations (e.g. start downloads or enable location services).

    This solution allows you to have several activities on the back stack, and doesn't require any permissions to implement.

    This solution works well if you use an event bus too, as your timer can simply fire an event and various parts of your app can respond accordingly.

    0 讨论(0)
提交回复
热议问题