App이 foreground 인지 background 인지 구별하기

android 2017. 3. 30. 22:24

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드 App을 만들다 보면은 App이 background로 내려가는 시점을 알아야 할 때가 있다. 

그런데, 안드로이드에서는 Home 버튼을 눌렀는지 알 수 있는 방법이 없어서 약간의 편법을 사용해야 한다. 



먼저 고전적인 방밥으로는 ActivityManager를 이용하는 방법이다. 

코드로 보면 아래와 같다. 


private boolean isAppIsInBackground(Context context) {
    boolean isInBackground = true;
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) {
        List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
            if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                for (String activeProcess : processInfo.pkgList) {
                    if (activeProcess.equals(context.getPackageName())) {
                        isInBackground = false;
                    }
                }
            }
        }
    } else {
        List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        if (componentInfo.getPackageName().equals(context.getPackageName())) {
            isInBackground = false;
        }
    }

    return isInBackground;
}


키캣미만에서는 RunningTaksInfo를 이용하고, 키캣이상에서는 RunningAppProcessInfo 를 이용하는 방식이다. 그런데 이 방색을 사용할때는  GET_TASKS 권한을 AndroidManifest.xml에 추가해야 하는데,  GET_TASKS 권한이 deprecated 되었다. 



그래서 다른 방식으로 사용하는것이 Activity의 onStart(), onStop() 함수를 오버라이드(override) 해서 count 하는 방식이다. 대략적인 코드는 아래와 같은 모습이다. 


public class BaseActivity extends Activity {
public static int foregroundCount = 0; // 전역 count 변수

@Override
protected void onStart() {
    super.onStart();
    foregroundCount = foregroundCount+ 1;
}


@Override
protected void onStop() { super.onStop(); foregroundCount = foregroundCount - 1;
} }


Application에서 사용하는 모든 Activity가 BaseActivity를 상속받게 하고, foregroundCount 가 1이상이면 foreground로 볼 수 있는 것이다. 

Activity가 많다면 은근히 작업이 많아 질 수도 있고, 나주에 추가되는 Activity에서 BaseActivity 로부터의 상속을 빼먹으면 버그가 발생하기 쉬운 방식이다. 



그럼 좀 더 안전한 방법은 없을까? 

앱에있는 Application 클래스를 이용하는 방법이 있는데, 

먼저 background에 있는지 체크하는 방법을 알아보자 


public class MyApplication extends Application {
    // ...
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
        if (level == TRIM_MEMORY_UI_HIDDEN) {
           isBackground = true;
           notifyBackground();
        }
    }
}


그런데, onTrimMemory 함수는 screen off 상태일때는 호출이 안되므로, 아래처럼 리시버를 등록해서 체크해야 한다. (screen off 상태는 전원버튼을 눌러서 화면을 끄는것을 말한다. ) 


public class MyApplication extends Application {
  // ...
  @Override
    public void onCreate() {
        super.onCreate();
        // ...
        IntentFilter screenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
        registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
              if (isBackground) {
                  isBackground = false;
                  notifyForeground();
              }
            }
        }, screenOffFilter);
      }
}


이렇게 하면 background 상태는 체크가 되는데, foreground 상태는 어떻게 알아 낼 수 있을까?

간단하게 ActivityLifecycleCallback() 함수를 이용하면 된다. 


public class MyApplication extends Application {
    // ...
    @Override
       public void onCreate() {
           super.onCreate();

     registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
               // ...
               @Override
               public void onActivityResumed(Activity activity) {
                 if (isBackground) {
                     isBackground = false;
                     notifyForeground();
                 }
               }
               // ...
           });
       }
       // ...
}



이상으로 App이 foreground에 있는지, background에 있는지 체크하는 방법에 대해서 

1. ActivityManager를 이용하는 고전적인 방법 

2. Activity의 onStart(), onStop() 을 활용한 방법

3. Application의 onTrimMemory(), registerActivityLifecycleCallbacks() 를 활용하는 방법

으로 알아 보았습니다. 





: