Programming

안드로이드 응용 프로그램이 전경에 있는지 확인하십시오.

procodes 2020. 8. 18. 19:16
반응형

안드로이드 응용 프로그램이 전경에 있는지 확인하십시오. [복제]


이 질문에 대한 많은 답변을 봤는데, 단일 활동에 관한 것입니다. 전체 앱이 포 그라운드에서 실행 중인지 여부를 확인하는 방법은 무엇입니까?


원하는 것을 이해하지 못하지만 현재 포 그라운드 / 백그라운드 애플리케이션을 ActivityManager.getRunningAppProcesses()호출로 감지 할 수 있습니다 .

같은 것,

class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {

  @Override
  protected Boolean doInBackground(Context... params) {
    final Context context = params[0].getApplicationContext();
    return isAppOnForeground(context);
  }

  private boolean isAppOnForeground(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    if (appProcesses == null) {
      return false;
    }
    final String packageName = context.getPackageName();
    for (RunningAppProcessInfo appProcess : appProcesses) {
      if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
        return true;
      }
    }
    return false;
  }
}

// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();

오해가 있으면 알려주세요 ..

업데이트 : 이 질문을보세요 . 백그라운드 작업 또는 서비스에서 현재 포 그라운드 애플리케이션 결정에 대한 자세한 정보 ..

감사..


@ user370305의 대답은 오류가 발생하기 쉬우 며 Android OS 개발자가 권장하지 않습니다 ( https://groups.google.com/forum/#!msg/android-developers/zH-2bovZSLg/L2YM8Z1N-HwJ 확인 ).

훨씬 더 간단한 접근 방식이 있습니다.

모든 활동이 확장 하는 BaseActivity에서 :

protected static boolean isVisible = false;

@Override
public void onResume() {
   super.onResume();
   setVisible(true);
}

@Override
public void onPause() {
    super.onPause();
    setVisible(false);
}

응용 프로그램 활동이 포 그라운드에 있는지 확인해야 할 때마다 확인하십시오. isVisible();

이 접근 방식을 이해하려면 side-by-side 활동 수명주기에 대한 답변을 확인하십시오. Activity side-by-side 수명주기


다음과 같이 지금까지 내가 찾은 가장 깔끔하고 더 이상 사용되지 않는 방법입니다.

@Override
public boolean foregrounded() {
    ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
    ActivityManager.getMyMemoryState(appProcessInfo);
    return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
}

SDK 16+에서만 작동합니다.

수정 :

솔루션에서 다음 코드를 제거했습니다.

KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
// App is foreground, but screen is locked, so show notification
return km.inKeyguardRestrictedInputMode();

화면이 잠긴 경우 알림을받지 못하기 때문입니다. 프레임 워크를 살펴 봤는데 그 목적이 명확하지 않습니다. 나는 그것을 제거 할 것이다. 프로세스 정보 상태를 확인하는 것으로 충분합니다 :-)


새로운 Android Architecture of Lifecycle 확장을 사용하면이를 최대한 쉽게 달성 할 수 있습니다.

build.gradle 파일에서이 종속성을 가져와야합니다.

dependencies {
    implementation "android.arch.lifecycle:extensions:1.1.0"
}

그런 다음 Application 클래스에서 다음을 사용하십시오.

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        Log.d("MyApp", "App in background")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        Log.d("MyApp", "App in foreground")
    }
}

마지막으로 AndroidManifest.xml 파일을 다음으로 업데이트하십시오.

<application
    android:name=".ArchLifecycleApp"
    //Your extra code
    ....>
</application>

이제 Application이 Foreground 또는 Background로 이동할 때마다 선언 된 두 메서드와 관련된 로그를 받게됩니다.


실행중인 프로세스에서 패키지 필터를 사용해 보았습니다. 그러나 그것은 매우 이상합니다. 그 대신 새로운 솔루션을 시도했으며 완벽하게 작동합니다. 이 모듈을 통해 여러 번 확인하고 완벽한 결과를 얻었습니다.

private int numRunningActivities = 0;

 public void onCreate() {
        super.onCreate();
this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

                @Override
                public void onActivityStarted(Activity activity) {
                    numRunningActivities++;
                    if (numRunningActivities == 1) {
                        LogUtils.d("APPLICATION", "APP IN FOREGROUND");
                    }

                }

                @Override
                public void onActivityStopped(Activity activity) {

                    numRunningActivities--;
                    if (numRunningActivities == 0) {
                       Log.e("", "App is in BACKGROUND") 
                    }
                }


                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
                }

                @Override
                public void onActivityResumed(Activity activity) {
                }

                @Override
                public void onActivityPaused(Activity activity) {
                }

                @Override
                public void onActivityDestroyed(Activity activity) {
                }

                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                }
            });
}

앱이 백그라운드 또는 포 그라운드에 있는지 확인하십시오. 이 메서드는 앱이 백그라운드에 있으면 true를 반환합니다.

먼저 AndroidManifest.xml에 GET_TASKS 권한을 추가하십시오.

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

Android 아키텍처 구성 요소 라이브러리는 ProcessLifecycleOwner를 사용하여 onStart 및 onStop 이벤트에 대한 전체 애플리케이션 프로세스에 대한 리스너를 설정할 수 있습니다. 이를 수행하려면 애플리케이션 클래스가 LifecycleObserver 인터페이스를 구현하도록하고 onStop 및 onStart에 대한 주석을 포 그라운드 및 백그라운드 메소드에 추가하십시오.

class ArchLifecycleApp : Application(), LifecycleObserver {

    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        Log.d("Awww", "App in background")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onAppForegrounded() {
        Log.d("Yeeey", "App in foreground")
    }

}

기본 활동 클래스를 생성하여 이에 대한 간단한 해결책을 찾았습니다. u는 다음에서 모든 활동 클래스를 확장해야합니다.

public class BaseActivity extends ActionBarActivity {

@Override
protected void onResume() {
    ApplicationStateChecker.view_resumed(this);
    super.onResume();
}

@Override
protected void onStop() {
    ApplicationStateChecker.view_stopped(this);
    super.onStop();

}

@Override
protected void onPause() {
    ApplicationStateChecker.view_paused(this);
    super.onPause();

}

}

ApplicationStateChecker 클래스 :

public class ApplicationStateChecker {

private  static final String _pause_string = "paused";
private  static final String _resume_string = "resumed";

private static String _view_lastState;
private static boolean _from_background = true;

public static void view_paused(Activity activity){
    _view_lastState = _pause_string;
}

public static void view_stopped(Activity activity){

    if (  _view_lastState.equals(_pause_string) ){
        //if stop called and last event was pause then app is brought to background
        _from_background = true;
    }  //if

}

public static void view_resumed(Activity activity){

    if (  _from_background ) {
       //Do your stuff here , app is brought to foreground 

    }  //if

    _from_background = false;
    _view_lastState = _resume_string;
}

cesards의 대답은 정확하지만 API> 15에만 해당됩니다. 낮은 API 버전의 경우 getRunningTasks()방법 을 사용하기로 결정했습니다 .

   private boolean isAppInForeground(Context context)
    {
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
        {
            ActivityManager am = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
            ActivityManager.RunningTaskInfo foregroundTaskInfo = am.getRunningTasks(1).get(0);
            String foregroundTaskPackageName = foregroundTaskInfo.topActivity.getPackageName();

            return foregroundTaskPackageName.toLowerCase().equals(context.getPackageName().toLowerCase());
        }
        else
        {
            ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();
            ActivityManager.getMyMemoryState(appProcessInfo);
            if (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE)
            {
                return true;
            }

            KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
            // App is foreground, but screen is locked, so show notification
            return km.inKeyguardRestrictedInputMode();
        }
    }

모두에게 효과가 있는지 알려주세요.


이에 대한 전역 콜백은 없지만 각 활동에 대해 onStop ()입니다. 원자 정수를 엉망으로 만들 필요가 없습니다. 시작된 활동의 수와 함께 전역 정수를 가지고 모든 활동에서 onStart ()에서 증가시키고 onStop ()에서 감소시킵니다.

public class BaseActivity extends ActionBarActivity {
public static int count = 0;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}


@Override
protected void onStart() {
    super.onStart();
    count = count + 1;
    Log.d(TAG, "onStart" + count);
    if (count == 1) {

       Toast.makeText(getApplicationContext(), "online", Toast.LENGTH_SHORT).show();

    }

}



protected void onStop() {
    super.onStop();
    count = count - 1;
    if (count == 0) {

        Toast.makeText(getApplicationContext(), "offline", Toast.LENGTH_SHORT).show();

    }
}


}

Application 클래스에서 ActivityLifecycleCallbacks를 사용해보십시오.


다음은 최신 Android SDK에 대한 업데이트 된 솔루션입니다.

String PackageName = context.getPackageName();
        ActivityManager manager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        ComponentName componentInfo;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            List<ActivityManager.AppTask> tasks = manager.getAppTasks();
            componentInfo = tasks.get(0).getTaskInfo().topActivity;
        }
        else
        {
            List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(1);
            componentInfo = tasks.get(0).topActivity;
        }

        if (componentInfo.getPackageName().equals(PackageName))
            return true;
        return false;

도움이 되었기를 바랍니다. 감사합니다.


getRunningTasks () 의 솔루션 기반 은 최신 Android 버전에서 작동 하지 않으며 getRunningTasks () 는 API 레벨 21에서 지원 중단되었습니다. 여전히 사용 되더라도 앱이 포 그라운드에 있는지 확인하기에 충분한 정보를 반환하지 않습니다.

대신 Application 클래스를 확장하고 Application.ActivityLifecycleCallbacks를 사용하여 애플리케이션 가시성 상태를 추적하십시오.

public class MyApplication extends Application {
    static final String APP_STATE_FOREGROUND = "com.xxx.appstate.FOREGROUND";
    static final String APP_STATE_BACKGROUND = "com.xxx.appstate.BACKGROUND";
    private static int m_foreground = -1;
    private Handler m_handler = new Handler();
    private Runnable m_guard;

    public static boolean isForeground() {
        return m_foreground == 1;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {

            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {
            }

            @Override
            public void onActivityStarted(Activity activity) {
            }

            @Override
            public void onActivityResumed(Activity activity) {
                if(m_guard != null) {
                    m_handler.removeCallbacks(m_guard);
                    m_guard = null;
                }
                if(m_foreground == 1)
                    return;
                m_foreground = 1;
                sendBroadcast(new Intent(APP_STATE_FOREGROUND));
            }

            @Override
            public void onActivityPaused(Activity activity) {
                if(m_foreground == 0)
                    return;
                /*
                 * Use a 400ms guard to protect against jitter
                 * when switching between two activities
                 * in the same app
                 */
                m_guard = new Runnable() {
                    @Override
                    public void run() {
                        if(m_foreground == 1) {
                            m_foreground = 0;
                            sendBroadcast(new Intent(APP_STATE_BACKGROUND));
                        }
                    }
                };
                m_handler.postDelayed(m_guard, 400);
            }

            @Override
            public void onActivityStopped(Activity activity) {
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
            }
        });
    }
}

400ms 가드 타이머를 사용하면 동일한 앱에서 활동을 전환 할 때 백그라운드 상태가 잘못 감지되지 않습니다. 배경 / 전경 상태는 다음을 사용하여 언제든지 쿼리 할 수 ​​있습니다.

MyApplication.isForeground();

클래스는 상태 전환에 관심이있는 경우 브로드 캐스트 이벤트를 수신 할 수도 있습니다.

private static IntentFilter m_appStateFilter;

static {
    m_appStateFilter = new IntentFilter();
    m_appStateFilter.addAction(MyApplication.APP_STATE_FOREGROUND);
    m_appStateFilter.addAction(MyApplication.APP_STATE_BACKGROUND);
}

private BroadcastReceiver m_appStateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(MyApplication.APP_STATE_FOREGROUND)) {
            /* application entered foreground */
        } else if (action.equals(MyApplication.APP_STATE_BACKGROUND)) {
            /* application entered background */
        }
    }
};
registerReceiver(m_appStateReceiver, m_appStateFilter);

아래 솔루션은 API 레벨 14 이상에서 작동합니다.

Backgrounding ComponentCallbacks2 — 문서를 보는 것은 이것을 어떻게 사용할 것인지 100 % 명확하지 않습니다. 그러나 자세히 살펴보면 onTrimMemory 메서드가 플래그로 전달되는 것을 알 수 있습니다. 이러한 플래그는 일반적으로 메모리 가용성과 관련이 있지만 우리가 관심을 갖는 것은 TRIM_MEMORY_UI_HIDDEN입니다. UI가 숨겨져 있는지 확인함으로써 앱이 현재 백그라운드에 있다고 가정 할 수 있습니다. 명확하지는 않지만 작동합니다.

Foregrounding ActivityLifecycleCallbacks — onActivityResumed를 재정의하고 현재 애플리케이션 상태 (Foreground / Background)를 추적하여이를 사용하여 전경을 감지 할 수 있습니다.

사용자 정의 Application 클래스에 의해 구현 될 인터페이스 생성

interface LifecycleDelegate {
    fun onAppBackgrounded()
    fun onAppForegrounded()
}

ActivityLifecycleCallbacks 및 ComponentCallbacks2를 구현하고 onActivityResumed 및 onTrimMemory 메서드를 재정의 할 클래스를 만듭니다.

// Take an instance of our lifecycleHandler as a constructor parameter
class AppLifecycleHandler(private val lifecycleDelegate: LifecycleDelegate) 
: Application.ActivityLifecycleCallbacks, ComponentCallbacks2 // <-- Implement these 
  {
private var appInForeground = false

      // Override from Application.ActivityLifecycleCallbacks
    override fun onActivityResumed(p0: Activity?) {
       if (!appInForeground) {
          appInForeground = true
          lifecycleDelegate.onAppForegrounded()
       }
    }

      // Override from ComponentCallbacks2
    override fun onTrimMemory(level: Int) { 
       if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
       // lifecycleDelegate instance was passed in on the constructor
          lifecycleDelegate.onAppBackgrounded()
       }
    }
}

이제 우리가해야 할 일은 사용자 정의 Application 클래스가 LifecycleDelegate 인터페이스를 구현하고 등록하는 것입니다.

class App : Application(), LifeCycleDelegate {

    override fun onCreate() {
        super.onCreate()
        val lifeCycleHandler = AppLifecycleHandler(this)
        registerLifecycleHandler(lifeCycleHandler)
    }

    override fun onAppBackgrounded() {
        Log.d("Awww", "App in background")
    }

    override fun onAppForegrounded() {
        Log.d("Yeeey", "App in foreground")
    }

    private fun registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) {
        registerActivityLifecycleCallbacks(lifeCycleHandler)
        registerComponentCallbacks(lifeCycleHandler)
    }

}

Manifest에서 CustomApplicationClass를 설정하십시오.

<application
        android:name=".App"

Android 19에서 다음과 같이 Application 클래스의 onCreate ()에 앱 수명주기 콜백을 등록 할 수 있습니다.

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new AppLifecycleCallback());
}

AppLifecycleCallback은 다음과 같습니다.

class AppLifecycleCallback implements Application.ActivityLifecycleCallbacks {
    private int numStarted = 0;

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

    }

    @Override
    public void onActivityStarted(Activity activity) {
        if (numStarted == 0) {
           //app went to foreground
        }
        numStarted++;
    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        numStarted--;
        if (numStarted == 0) {
            // app went to background
        }
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}

참고 URL : https://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not

반응형