백그라운드에서 Android 애플리케이션이 실행 중인지 확인


329

배경에 따르면, 현재 응용 프로그램의 활동이 사용자에게 보이지 않는 것을 의미합니까?



7
나는 여기에 혼란 스럽다. 왜 안드로이드가 응용 프로그램 클래스에서 간단한 재정의를 제공 할 수 없습니까? 플랫폼 수준에서 이것을 아는 것이 너무 어렵습니까? @Override protected void onApplicationSentToBackground () {}
Chuck D

2
@ChuckD-그것은 말이됩니다 .Android SDK는 때때로하지 않는 것처럼 보입니다. : /
Mark


1
iOS는 이것을 스페이드로 가지고 있는데 왜 구글이 그렇게 어렵게 만드는지 잘 모르겠습니다. 그것은 분명한 요구입니다.
Jerry Destremps 2016 년

답변:


388

애플리케이션이 백그라운드에서 실행 중인지 여부를 감지하는 몇 가지 방법이 있지만 그 중 하나만 완전히 신뢰할 수 있습니다.

  1. 올바른 솔루션 (신용은 Dan , CommonsWareNeTeInStEiN으로 이동 ) , 메소드를
    사용하여 애플리케이션의 가시성을 추적하십시오 . 다른 클래스에 "가시성"상태를 저장하십시오. 올바른 선택은 또는의 자체 구현입니다 ( 서비스에서 활동 가시성을 확인하려는 경우이 솔루션의 변형 도 있습니다 ). 사용자 정의 구현 클래스 (음 정적 방법) :Activity.onPauseActivity.onResumeApplicationService
     

    ApplicationisActivityVisible()

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

    다음에 응용 프로그램 클래스를 등록하십시오 AndroidManifest.xml.

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

    추가 onPauseonResume모든에 Activity프로젝트 (당신이 원하신다면 당신은 당신의 활동에 대한 공통 조상을 만들 수 있지만, 활동이 이미 연장 된 경우 MapActivity/ ListActivity등 여전히 손으로 다음 쓸 필요) :

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

     

    ActivityLifecycleCallbacks 업데이트 는 API 레벨 14 (Android 4.0)에서 추가되었습니다. 이를 사용하여 애플리케이션 활동이 현재 사용자에게 표시되는지 여부를 추적 할 수 있습니다. 자세한 내용은 아래 Cornstalks의 답변을 확인하십시오.


  2. 내가 다음 해결책을 제안하는 데 잘못 사용한 것 :

    레코드 ActivityManager.getRunningAppProcesses()목록을 리턴하는 현재 포 그라운드 / 백그라운드 애플리케이션을 감지 할 수 있습니다 RunningAppProcessInfo. 응용 프로그램이 전경에 있는지 확인 RunningAppProcessInfo.importance하는 RunningAppProcessInfo.IMPORTANCE_FOREGROUND동안 whileRunningAppProcessInfo.processName 과 동일한 지 하십시오. 응용 프로그램 패키지 이름과 같습니다.

    또한 ActivityManager.getRunningAppProcesses()응용 프로그램 UI 스레드에서 호출하면 IMPORTANCE_FOREGROUND실제로 포 그라운드에 있는지 여부에 관계없이 작업의 중요도 를 반환합니다 . 백그라운드 스레드에서 (예 :을 통해 AsyncTask) 호출하면 올바른 결과가 반환됩니다.

    이 솔루션은 작동하지만 실제로는 대부분 작동하지만 사용하지 않는 것이 좋습니다. 그리고 여기에 이유가 있습니다. Dianne Hackborn은 다음과 같이 썼습니다 .

    이러한 API는 애플리케이션이 UI 흐름을 기반으로하는 것이 아니라 사용자에게 실행중인 앱 또는 작업 관리자 등을 표시하는 것과 같은 작업을 수행하기위한 것입니다.

    그렇습니다. 이러한 것들에 대한 목록이 메모리에 보관되어 있습니다. 그러나 다른 프로세스에서는 꺼져 있으며 사용자와 별도로 실행되는 스레드로 관리되며 (a) 올바른 결정을 내릴 시간을 보거나 (b) 돌아올 때까지 일관된 그림을 가질 수는 없습니다. 또한 "다음"활동에 대한 결정은 항상 스위치가 발생할 지점에서 수행되며, 정확한 시점 (활동 상태가 잠깐 동안 스위치를 수행하기 위해 잠긴 지점)까지는 아닙니다. 실제로 다음 일이 무엇인지 확실히 알고 있습니다.

    그리고 여기에서의 구현과 글로벌 행동이 미래에도 동일하게 유지되는 것은 아닙니다.

    나는 SO에 대한 답변을 게시하기 전에 이것을 읽었기를 바란다. 그러나 내 오류를 인정하기에는 너무 늦지 않았기를 바란다.

  3. 답변 중 하나에서 언급 된 또 다른 잘못된 솔루션
    Droid-Fu 라이브러리는 ActivityManager.getRunningTasks해당 isApplicationBroughtToBackground방법에 사용 합니다 . 위의 Dianne의 의견을 참조하고 해당 방법을 사용하지 마십시오.


4
홈 버튼을 눌렀는지 또는 다른 응용 프로그램이 초점을 얻었는지 알려면 1) 좋은 솔루션을 구현하십시오 . 2)에 OnStop요청합니다 isActivityVisible.
Brais Gabin

28
불행히도 귀하의 '올바른'솔루션이 작동하지 않습니다. 앱 내 활동을 순환하는 것을 고려하십시오. 그러면 'inForeground'플래그는 다음과 같이 진행됩니다. True, False (첫 번째 활동의 onPause와 두 번째 활동의 onResume 사이) 그리고 다시 True 등. 그러면 일종의 히스테리시스가 필요합니다.
Radu

14
모든 활동을 직접 제어 할 수없는 경우이 솔루션이 작동하지 않습니다. 예를 들어 타사 SDK의 활동이 있거나 ACTION_VIEW 인 텐트를 시작하는 경우가 있습니다.
user123321

66
안드로이드는 그런 난파선입니다. 아무도 누군가가 앱 레벨 데이터를 유지하고 싶을 것이라고 생각하지 않았습니까? 휴식을 취하십시오

8
이 질문에 대한 실제 답변은 "올바로 확인할 수 없습니다"입니다. 소위 '올바른'솔루션은 최선의 해결 방법이므로 ActivityLifecycleCallbacks를 사용하는 것입니다. "포 그라운드에 없음"으로 등록 된 활동 간 전환을 고려해야합니다. 당신이 그런 간단한 것을 확인할 수 없다는 것이 내 마음을
serine

263

이 답변을 사용하지 마십시오

user1269737의 답변은 올바른 (Google / Android 승인) 방법 입니다. 그들의 답변을 읽고 +1하십시오.

나는 후손을 위해 원래의 대답을 여기에 남겨 둘 것이다. 이것은 2012 년에 가장 잘 사용되었지만 이제는 Android가이를 올바르게 지원합니다.

원래 답변

열쇠는 사용 중입니다 ActivityLifecycleCallbacks(Android API 레벨 14 (Android 4.0)가 필요합니다). 중지 된 활동 수가 시작된 활동 수와 같은지 확인하십시오. 동일하면 응용 프로그램의 배경 지식이있는 것입니다. 시작된 활동이 더 있으면 응용 프로그램이 여전히 표시됩니다. 일시 정지 된 활동보다 재개 된 경우 응용 프로그램이 표시 될뿐만 아니라 포 그라운드에도 있습니다. 활동은 다음과 같은 3 가지 주요 상태로 표시됩니다. 표시 및 포 그라운드, 표시되지만 포 그라운드에서는 표시되지 않고 포 그라운드에서는 표시되지 않습니다 (예 : 백그라운드).

이 방법에 대한 정말 좋은 점은 비동기 문제가되지 않는다는 것입니다 getRunningTasks()않지만, 당신은 또한 모든를 수정할 필요가 없습니다 Activity에서 설정 / 해제 뭔가를 응용 프로그램에서 onResumed()/ onPaused(). 자체 포함 된 몇 줄의 코드 일 뿐이며 전체 응용 프로그램에서 작동합니다. 또한 펑키 권한도 필요하지 않습니다.

MyLifecycleHandler.java :

public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
    // I use four separate variables here. You can, of course, just use two and
    // increment/decrement them instead of using four and incrementing them all.
    private int resumed;
    private int paused;
    private int started;
    private int stopped;

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
    }

    @Override
    public void onActivityPaused(Activity activity) {
        ++paused;
        android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
    }

    @Override
    public void onActivityStopped(Activity activity) {
        ++stopped;
        android.util.Log.w("test", "application is visible: " + (started > stopped));
    }

    // If you want a static function you can use to check if your application is
    // foreground/background, you can use the following:
    /*
    // Replace the four variables above with these four
    private static int resumed;
    private static int paused;
    private static int started;
    private static int stopped;

    // And these two public static functions
    public static boolean isApplicationVisible() {
        return started > stopped;
    }

    public static boolean isApplicationInForeground() {
        return resumed > paused;
    }
    */
}

MyApplication.java :

// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        // Simply add the handler, and that's it! No need to add any code
        // to every activity. Everything is contained in MyLifecycleHandler
        // with just a few lines of code. Now *that's* nice.
        registerActivityLifecycleCallbacks(new MyLifecycleHandler());
    }
}

@Mewzer는이 답변에 대해이 답변에 대해 모든 사람들에게 응답하고 싶은 좋은 질문을했습니다.

onStop()메모리 부족 상황에서는 호출되지 않습니다. 그게 문제입니까?

아니요. 문서는 다음과 같이 onStop()말합니다.

onPause () 메소드를 호출 한 후 활동 프로세스를 계속 실행할 수있는 메모리가 부족한 메모리가 부족한 상황에서는이 메소드를 호출 할 수 없습니다.

여기서 핵심은 "활동의 프로세스를 계속 실행하는 것"입니다. 메모리가 부족한 상황에 도달하면 프로세스는 실제로 활동이 아니라 종료됩니다. 이는 a) 프로세스가 종료 된 경우 어쨌든 백그라운드를 확인할 수 없으며 b) 프로세스가 다시 시작되는 경우 (새로운 활동이 작성 되었기 때문에) 에 대한 변수 (정적이든 아니든) MyLifecycleHandler는로 재설정됩니다 0.

구성 변경에도 적용됩니까?

기본적으로 아니요. 매니페스트 파일에서 명시 적으로 설정하고 configChanges=orientation|screensize( |다른 것을 사용하여) 구성 변경을 처리해야합니다. 그렇지 않으면 활동이 삭제되고 다시 작성됩니다. 이를 설정하지 않으면 활동의 메소드가 다음 순서로 호출됩니다 onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. 보시다시피 겹침이 없습니다 (일반적으로 두 활동을 전환 할 때 두 활동이 아주 짧게 겹칩니다. 이는 백그라운드 감지 방법이 작동하는 방식입니다). 이 문제를 해결하려면 configChanges활동이 파괴되지 않도록 설정해야합니다 . 다행히도 설정해야했습니다configChanges전체 활동이 화면 회전 / 크기 조정에서 파괴되는 것이 바람직하지 않았기 때문에 이미 모든 프로젝트에 이미 있었기 때문에 문제가되지 않았습니다. (내 기억을 상쾌하게하고 나를 고쳐 주신 dpimka에 감사드립니다!)

참고 사항 :

이 답변에서 "배경"이라고 말하면 "앱이 더 이상 표시되지 않습니다."라는 의미입니다. 안 드 로이드 활동은 아직 보이지 않지만 (예 : 투명한 알림 오버레이가있는 경우) 보이지 않습니다. 그렇기 때문에이 답변을 업데이트했습니다.

포 그라운드에 아무것도없는 곳에서 활동을 전환 할 때 Android에 이상한 순간이 있다는 것을 아는 것이 중요합니다 . 이러한 이유로, 동일한 앱에서 액티비티간에 전환 할 때 애플리케이션이 포 그라운드에 있는지 확인하면 포 그라운드에 있지 않다는 메시지가 표시됩니다 (앱이 여전히 활성 앱이고 표시됨) ).

당신의 앱이 포 그라운드에있는 경우 확인할 수 있습니다 ActivityonPause()방법 super.onPause() . 내가 방금 말한 이상한 림보 상태를 기억하십시오.

이후ActivityonStop()메소드 에서 앱이 표시되는지 (즉, 백그라운드에없는 경우) 확인할 수 있습니다 . super.onStop()


1
이것은 흥미로워 보이지만 메모리 부족 상황에서는 어떻게됩니까? onStop ()이 호출된다는 보장은 없습니다. onStop ()이 호출되지 않고 중지 된 카운터가 증가하지 않는 상황에 처할 수 있습니까? 이는 백그라운드 검사가 더 이상 신뢰할 수 없음을 의미합니까? 아니면 이런 일이 일어나지 않을까요?
Mewzer

1
또한 이것은 구성 변경을 무시합니까? 또는 구성 변경 (예 : 방향 변경)의 결과로 활동이 재 작성되는 경우 애플리케이션이 백그라운드로 간주됩니까? 미안하지만, 질문에 대해서는 당신이 무언가에 있다고 생각하며 이것이 가장자리 케이스에서 작동하는지 알고 싶습니다.
Mewzer

1
@Mewzer : 의견으로 답변을하려고했지만이 답변을 얻으려면 약간의 타이핑이 필요하므로 몇 분 후에 다시 확인하면 답변을 수정하겠습니다.
Cornstalks

1
@Mewzer : 지금 답을 찾아야합니다. 다른 질문이 있으면 알려주세요!
Cornstalks

2
@Mewzer : 난 그냥 당신이에 관심이있을 수 있다는 메모를 추가 구체적으로 배경 처리를 확인하십시오. onStop()super.onStop(). 에서 배경을 확인하지 마십시오 onPause().
Cornstalks

186

GOOGLE SOLUTION- 이전 솔루션처럼 해킹이 아닙니다. 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
    }

}


자바:

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

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

라이프 사이클 관련 아키텍처 구성 요소에 대한 자세한 내용은 여기 ( https://developer.android.com/topic/libraries/architecture/lifecycle)를 참조하십시오.


10
이것은 정답 일 것입니다! 그것은 매력처럼 일했다 : D
JaviOverflow

2
이것은 완벽하게 작동하며, 약간 수정하여이 클래스 외부에서 더 쉽게 전경 / 배경 상태에 액세스 companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }할 수 있습니다 . 그러면 다음과 같이 전경 상태를 얻을 수 있습니다.ArchLifecycleApp.isForeground()
Jose Jet

2
오, 이건 내 옛 대답보다 훨씬 낫다. 내게 +1 해주세요. 사람들이 당신을 가리 키도록 답변을 업데이트했습니다.
Cornstalks

2
이것이 정답이지만 콜백을 구현할 필요는 없지만 원할 때마다 ProcessLifecycleOwner를 쿼리 할 수 ​​있습니다. stackoverflow.com/a/52678290/6600000
Keivan Esbati

2
문서가 말했듯이 The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , 이것은 multiple processes앱에서 작동하지 않습니다. 우아하게 달성 할 수있는 API가 있습니까?
acntwww

23

지원 라이브러리 버전 26부터 ProcessLifecycleOwner 를 사용할 수 있습니다 ( 예 : 여기 에 설명 된대로 종속성에 추가) .

dependencies {
    def lifecycle_version = "1.1.1"

    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData).
    //     Support library depends on this lightweight import
    implementation "android.arch.lifecycle:runtime:$lifecycle_version"
    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
}

그런 다음 ProcessLifecycleOwner앱 상태, 예를 원할 때마다 쿼리하십시오 .

//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;

//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);

2
고마워, 이것은 fcm을 사용할 때 특별히 코드의 어떤 부분에도 적합한 가장 쉽고 쉬운 방법입니다.
Mihae Kheel 2016

응용 프로그램이 완전히 닫히면 첫 번째 방법은 무엇을 반환합니까?
Evgeniy Mishustin

@EvgeniyMishustin은 응용 프로그램의 현재 상태에 따라 다르지만 일반적으로 CREATED 다음에 DESTROYED가 표시되면 새 이벤트가 수신되지 않습니다.
Keivan Esbati

그렇다면 IF 앱이 백그라운드 (전경)에있는 것을 볼 수있는 "IF"문은 어디에 있습니까 ???
ekashking

@ekashking은 if 문에 전체 문장을 넣었습니다. 예를 들어 : (ProcessLifecycleOwner.get () getLifecycle () getCurrentState () isAtLeast (Lifecycle.State.STARTED는)...) => 애플리케이션 전경 인 경우
Keivan Esbati

20

Android API 16부터 앱이 포 그라운드에 있는지 확인하는 간단한 방법이 있습니다. 완벽하지는 않지만 안드로이드의 방법은 절대 아닙니다. 이 방법은 서비스가 서버로부터 업데이트를 수신 할 때 사용하기에 충분하며 알림 표시 여부를 결정해야합니다 (UI가 포 그라운드 인 경우 사용자는 알림없이 업데이트를 알 수 있음).

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

이 코드는 Service 클래스 또는 다른 클래스 (예 : Application 클래스) 내에 있어야합니까? 고마워
우피

.. 마지막 줄로 사용하고자하는 곳은 부울입니다.
AO_

푸시 알림에 대한 AWS Android SDK와 동일한 방법입니다.
spakmad

"서비스 제한을위한 배경 정의는 메모리 관리에서 사용되는 정의와 다릅니다. 응용 프로그램은 메모리 관리와 관련하여 백그라운드에 있지만 서비스를 시작하는 기능과 관련하여 전경에있을 수 있습니다.) " developer.android.com/about/versions/oreo/background.html (
ARLabs

감사합니다. JobService서비스가 백그라운드에서 실행되고 있음을 감지 하기 위해이 코드를 사용할 수있었습니다 .
Michael Osofsky

17

Idolon의 대답은 오류가 발생하기 쉽고 여기에서 안드로이드 응용 프로그램이 포 그라운드에 있는지 여부를 확인하는 것이 훨씬 더 복잡 합니까? 여기 백그라운드 작업이나 서비스에서 현재 전경 응용 프로그램을 결정

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

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

protected static boolean isVisible = false;

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


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

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

이 방법은 나란히 활동의 라이프 사이클이 답변을 확인 이해하려면 다음 작업을 나란히 라이프 사이클


3
Idolon's answer is error prone불행히도 나는 당신의 의견에 동의해야합니다. Google 그룹스에서 Dianne Hackborn의 의견을 바탕으로 답변을 업데이트했습니다. 자세한 내용은 확인해주세요.
Idolon

2
이것은 완벽한 솔루션 이 아닙니다 . 한 가지 시나리오는 사용자가 알림 패널을 풀다운 한 onPause경우 onStop, 및 onResume이벤트가 호출 되지 않는 것 입니다. 이 이벤트 중 어느 것도 발생하지 않으면 어떻게해야합니까?!


슬프게도 화면이 꺼져있을 때 활동이 시작되면이 코드가 잘못 작동합니다. 이 경우 onResume 및 onPause를 making isVisible = false라고합니다.
CoolMind

@CoolMind 백그라운드에서 활동을 시작할 유스 케이스를 설명해 주시겠습니까?
neteinstein

11

Application.ActivityLifecycleCallbacks 및 기타 여러 가지 를 사용하는 권장 솔루션을 시도했지만 예상대로 작동하지 않았습니다. Sarge 덕분에 아래에서 설명하는 매우 쉽고 간단한 솔루션을 생각해 냈습니다.

그들은 솔루션의 핵심 우리가 ActivityA 및 ActivityB을 가지고 우리가 ActivityA에서 ActivityB를 호출하는 경우 (그리고 전화를하지 않는 것이 이해의 사실이다 ActivityA.finish, 다음 ActivityB의)가 onStart()호출됩니다 전에 ActivityA onStop().

그것은 또한의 주요 차이 onStop()onPause()그 누구도 내가 읽은 기사에서 언급을하지 않았다.

따라서이 활동의 라이프 사이클 동작에 따라, 당신은 단순히 한 횟수를 셀 수 onStart()onPause()프로그램에서 호출되었다. 참고 Activity 프로그램의, 당신은 오버라이드 (override) 할 필요가 onStart()onStop()순서는, 증가 / 감소 정적 변수는 계산에 사용합니다. 아래는이 논리를 구현하는 코드입니다. 확장하는 클래스를 사용하고 Application있으므로 간단한 사용자 정의 클래스를 사용하여 구현할 수도 있지만 Manifest.xmlApplication 태그 내부 에서 선언하는 것을 잊지 마십시오 android:name=".Utilities".

public class Utilities extends Application
{
    private static int stateCounter;

    public void onCreate()
    {
        super.onCreate();
        stateCounter = 0;
    }

    /**
     * @return true if application is on background
     * */
    public static boolean isApplicationOnBackground()
    {
        return stateCounter == 0;
    }

    //to be called on each Activity onStart()
    public static void activityStarted()
    {
        stateCounter++;
    }

    //to be called on each Activity onStop()
    public static void activityStopped()
    {
        stateCounter--;
    }
}

이제 우리 프로그램의 각 활동에, 우리는 오버라이드 (override) onStart()하고 onStop()아래와 같이 및 증가 / 감소를 :

@Override
public void onStart()
{
    super.onStart();
    Utilities.activityStarted();
}

@Override
public void onStop()
{
    Utilities.activityStopped();
    if(Utilities.isApplicationOnBackground())
    {
        //you should want to check here if your application is on background
    }
    super.onStop();
}

이 논리를 사용하면 가능한 두 가지 경우가 있습니다.

  1. stateCounter = 0 : 중지 된 수는 시작된 활동 수와 같습니다. 즉, 애플리케이션이 백그라운드에서 실행 중임을 의미합니다.
  2. stateCounter > 0 : 시작 횟수가 중지 횟수보다 많으므로 애플리케이션이 포 그라운드에서 실행 중임을 의미합니다.

참고 : stateCounter < 0시작하기보다는 중지 된 활동이 더 많음을 의미하므로 불가능합니다. 이 경우에는 카운터를 증가 / 감소시키지 않는 것입니다.

당신은 갈 준비가되었습니다. 애플리케이션이 백그라운드에 있는지 확인해야합니다 onStop().


로 이동 if(Utilities.isApplicationOnBackground()) …합니다 Utilities. 그렇지 않으면 특정 활동 만 이벤트에 반응하기 때문입니다.
표시 이름

10

활동을 볼 수 있는지 여부를 판단 할 수있는 방법은 없습니다. 아마도 새로운 StackOverflow 질문을하여 사용자 경험을 통해 달성하려는 것이 무엇인지 설명해야하므로 대체 구현 아이디어를 제공 할 수 있습니다.


2
안드로이드에는 "Background Data"라는 설정이 있습니다. 이 설정은 응용 프로그램이 백그라운드에서 실행될 때 백그라운드 데이터 연결을 켭니다. 내 응용 프로그램에 대해 "배경 데이터"토글을 구현하고 싶습니다. 사용자에게 내 활동이 표시되지 않으면 서비스에서 데이터 전송을 중지하고 싶지만 내 활동 중 하나가 재개되는 순간, 데이터 전송 재개
cppdev

1
@cppdev : "데이터 전송"이에 의해 수행되기를 바랍니다 Service. 그렇다면 활동이 서비스에 나타나고 사라짐을 알리도록하십시오. (가)되면 Service어떤 활동을 볼 수 있다는 것을 결정하고, 그 시간의 일부 금액에 대한 그런 식으로 남아, 다음 논리적 인 정지 지점에서의 데이터 전송을 중지합니다. 예, 각 활동에 대한 코드가 필요하지만 현재 불가피한 AFAIK입니다.
CommonsWare

1
모든 활동간에 공통 코드를 복사하여 붙여 넣지 않으려면 라이프 사이클 메소드 MyActivityClass에서 상속 Activity하고 구현 하는 클래스를 작성하고 모든 활동이에서 상속되도록 할 수 있습니다 MyActivityClass. 이에 대한 일 것이다 PreferenceActivity또는 MapActivity비록 (볼 이 질문에 )
기욤 Brunerie에게

@CommonsWare 나는 OnPause () OnResume ()을 사용하여 활성화 여부를 시도했지만 백그라운드에서 실행되는 경우 내 앱이보기 화면에서 보이지 않는 경우 활성화 여부를 확인하는 방법
Manoj

@CommonsWare 나는 OnPause () OnResume ()을 사용하여 활성화 여부를 시도했지만 백그라운드에서 실행되는 경우 내 앱이보기 화면에서 보이지 않는 경우 활성화 여부를 확인하는 방법
Manoj

5

ComponentCallbacks2 를 사용 하여 앱이 백그라운드에 있는지 감지 할 수 있습니다 . BTW이 콜백은 API 레벨 14 (Ice Cream Sandwich) 이상 에서만 사용할 수 있습니다 .

메소드를 호출합니다.

public abstract void onTrimMemory (int level)

레벨이 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN앱이면 백그라운드에 있습니다.

당신은이 인터페이스를 구현할 수 있습니다 activity, service

public class MainActivity extends AppCompatActivity 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) {
        // app is in background
     }
   }
}

1
답변을 시도했지만 신뢰할 수는 없습니다. 화면이 잠겨 있거나 "전원"버튼을 눌러 화면을 잠글 때 onTrimMemory 콜백이 트리거되지 않습니다. 앱이 표시되고 상태 표시 줄 알림을 통해 다른 앱을 열면 항상 TRIM_MEMORY_UI_HIDDEN을 반환하지는 않습니다. 신뢰할 수있는 유일한 솔루션은 ActivityLifecycleCallbacks를 구현하고이를 사용 사례에 맞게 조정하는 것입니다.
velval

4

@Cornstalks를 기반으로 유용한 몇 가지 기능이 포함되어 있습니다.

추가 기능 :

  • AppLifecycleHandler.isApplicationVisible () 및 AppLifecycleHandler.isApplicationInForeground () 응용 프로그램의 어느 곳에서나 할 수 있도록 싱글 톤 패턴을 도입했습니다.
  • 중복 이벤트 처리 추가 (댓글 참조 // 가시성 변경에 대한 조치를 취하고 // 전경 변경에 대한 조치를 취함)

App.java

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

        registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
    }
}

AppLifecycleHandler.java

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
    private int resumed;
    private int started;

    private final String DebugName = "AppLifecycleHandler";

    private boolean isVisible = false;
    private boolean isInForeground = false;

    private static AppLifecycleHandler instance;

    public static AppLifecycleHandler getInstance() {
        if (instance == null) {
            instance = new AppLifecycleHandler();
        }

        return instance;
    }

    private AppLifecycleHandler() {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {
        ++resumed;
        android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

    @Override
    public void onActivityPaused(Activity activity) {
        --resumed;
        android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
        setForeground((resumed > 0));
    }

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

    @Override
    public void onActivityStarted(Activity activity) {
        ++started;
        android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    @Override
    public void onActivityStopped(Activity activity) {
        --started;
        android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
        setVisible((started > 0));
    }

    private void setVisible(boolean visible) {
        if (isVisible == visible) {
            // no change
            return;
        }

        // visibility changed
        isVisible = visible;
        android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);

        // take some action on change of visibility
    }

    private void setForeground(boolean inForeground) {
        if (isInForeground == inForeground) {
            // no change
            return;
        }

        // in foreground changed
        isInForeground = inForeground;
        android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);

        // take some action on change of in foreground

    }

    public static boolean isApplicationVisible() {
        return AppLifecycleHandler.getInstance().started > 0;
    }

    public static boolean isApplicationInForeground() {
        return AppLifecycleHandler.getInstance().resumed > 0;
    }
}

3

내가 생각해 낸 최고의 솔루션은 타이머를 사용합니다.

onPause ()에서 타이머를 시작하고 onResume ()에서 동일한 타이머를 취소하면 Timer의 인스턴스가 하나 있습니다 (일반적으로 Application 클래스에 정의 됨). 타이머 자체는 2 초 후에 (또는 적절하다고 생각되는 간격으로) Runnable을 실행하도록 설정되며, 타이머가 실행될 때 응용 프로그램을 백그라운드로 표시하는 플래그를 설정합니다.

타이머를 취소하기 전에 onResume () 메서드에서 백그라운드 플래그를 쿼리하여 모든 시작 작업을 수행 할 수 있습니다 (예 : 다운로드 시작 또는 위치 서비스 사용).

이 솔루션을 사용하면 백 스택에서 여러 가지 활동을 수행 할 수 있으며 구현 권한이 필요하지 않습니다.

이 솔루션은 타이머가 단순히 이벤트를 발생시킬 수 있고 앱의 다양한 부분이 그에 따라 응답 할 수 있으므로 이벤트 버스를 사용하는 경우에도 효과적입니다.


나는 이것이 최선의 (안타깝지만) 해결책이라고 생각하기 시작했다
dhaag23

그러나 이것은 내가 관리 한 최고의 솔루션입니다. 앱이 포 그라운드되지 않았을 때 블루투스 스캔을 중지해야했지만 사용자가 앱을 탐색 할 때 끊임없이 중지하고 시작하고 싶지 않기 때문에 일시 중지 또는 중지 또는 파괴를 사용할 수 없었습니다.
CaptRespect

3

개발자 활동을 "활동을 유지하지 마십시오"로 설정 한 경우 생성 된 활동 수만 검사하면 충분하지 않습니다. isSaveInstanceState 도 확인해야합니다 . 내 사용자 정의 메소드 isApplicationRunning () 확인은 Android 앱이 실행 중입니다.

여기 내 작업 코드 :

public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
    private int created;
    private boolean isSaveInstanceState;
    private static AppLifecycleService instance;

    private final static String TAG = AppLifecycleService.class.getName();

    public static AppLifecycleService getInstance() {
        if (instance == null) {
            instance = new AppLifecycleService();
        }
        return instance;
    }

    public static boolean isApplicationRunning() {
        boolean isApplicationRunning = true;
        if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
            isApplicationRunning = false;
        }
        return isApplicationRunning;
    }

    public static boolean isSaveInstanceState() {
        return AppLifecycleService.getInstance().isSaveInstanceState;
    }

    public static int getCountCreatedActvities() {
        return AppLifecycleService.getInstance().created;
    }

    private AppLifecycleService() {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        this.isSaveInstanceState = true;
    }

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

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

    @Override
    public void onActivityResumed(Activity activity) {   }

    @Override
    public void onActivityPaused(Activity activity) { }


    @Override
    public void onActivityStarted(Activity activity) { }

    @Override
    public void onActivityStopped(Activity activity) { }        

}

3

유일한 해결책은 다음과 같습니다.

MainActivity.java :

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java :

public class MyApp extends Application implements LifecycleObserver {

    public static MainActivity mainActivity = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onAppBackgrounded() {
        // app in background
        if (mainActivity != null) {
            ...
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onAppForegrounded() {
        // app in foreground
        if (mainActivity != null) {
            ...
        }
    }

}

이 솔루션으로 앱이 백그라운드인지 포 그라운드인지 여부에 따라 내 활동 (또는 조각)에 대한 IF 문 내에서 간단한 질문에 대한 대답을 어떻게 얻을 수 있는지 알 수 없습니다. "IF"문은 어디에 있습니까 ???
ekashking

2

CommonsWare 및 Key가 말한 내용을 피기 백하기 위해 Application 클래스를 확장하고 모든 활동이 onPause / onResume 메소드에서 호출되도록 할 수 있습니다. 이를 통해 어떤 활동이 보이는지 알 수 있지만 더 잘 처리 할 수 ​​있습니다.

당신이 생각하고있는 것을 정확하게 설명 할 수 있습니까? 백그라운드에서 실행한다고 말하면 현재 화면에 나타나지 않아도 응용 프로그램이 여전히 메모리에 남아 있다는 의미입니까? 서비스가 초점이 맞지 않을 때 서비스를보다 지속적으로 관리하는 방법으로 서비스를 사용하고 있습니까?


안드로이드에는 "Background Data"라는 설정이 있습니다. 이 설정은 응용 프로그램이 백그라운드에서 실행될 때 백그라운드 데이터 연결을 켭니다. 내 응용 프로그램에 대해 "배경 데이터"토글을 구현하고 싶습니다. 따라서 사용자에게 내 활동이 보이지 않으면 서비스에서 데이터 전송을 중지하고 싶지만 내 활동 중 하나가 재개되는 순간에 싶습니다. 데이터 전송 재개
cppdev

1
Application이없는 onPause()onResume().
CommonsWare

1
@CommonsWare 당신이 옳습니다, 나는 그들의 일시 중지 / 재개에서 응용 프로그램에 연락하는 각 개별 활동을 언급하고 있습니다. 이것은 기본적으로 당신이 당신의 답변에 대한 의견에 대해 공유 한 아이디어이지만, 더 똑똑한 움직임이라고 생각하는 서비스를 사용했습니다.
Dan

2

ActivityLifecycleCallbacks를 직접 구현했습니다. SherlockActivity를 사용하고 있지만 일반적인 활동 클래스에서는 작동 할 수 있습니다.

먼저, 활동 라이프 사이클을 추적하기위한 모든 메소드가있는 인터페이스를 작성 중입니다.

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

둘째, 내 응용 프로그램 클래스 에서이 인터페이스를 구현했습니다.

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

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

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

셋째, SherlockActivity에서 확장되는 클래스를 만들고 있습니다.

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityResumed(this);
        super.onResume();

    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityPaused(this);
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        nMyApplication.onActivityDestroyed(this);
        super.onDestroy();
    }

    @Override
    protected void onStart() {
        nMyApplication.onActivityStarted(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        nMyApplication.onActivityStopped(this);
        super.onStop();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        nMyApplication.onActivitySaveInstanceState(this, outState);
        super.onSaveInstanceState(outState);
    }   
}

넷째, SherlockActivity에서 확장되는 모든 클래스는 MySherlockActivity로 대체되었습니다.

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

이제 logcat에 MyApplication에서 만든 인터페이스 구현에 프로그래밍 된 로그가 표시됩니다.


1

대화 상자가 위에 오면 활동이 일시 중지되므로 모든 권장 솔루션이 반 솔루션입니다. 대화 상자에 대한 후크도 작성해야합니다.



1

공식 문서 :

시스템은 포 그라운드 앱과 백그라운드 앱을 구분합니다. (서비스 제한을위한 배경 정의는 메모리 관리에서 사용되는 정의와는 다릅니다. 앱은 메모리 관리 와 관련하여 백그라운드에있을 수 있지만 서비스를 시작하는 기능과 관련하여 포 그라운드에있을 수 있습니다.) 다음 중 하나에 해당하면 포 그라운드에있는 것으로 간주됩니다.

  1. 활동 시작 또는 일시 중지 여부에 관계없이 활동이 표시됩니다.
  2. 전경 서비스가 있습니다.
  3. 다른 포 그라운드 앱은 서비스 중 하나에 바인딩하거나 콘텐츠 공급자 중 하나를 사용하여 앱에 연결됩니다. 예를 들어 다른 앱이 앱에 바인딩 된 경우 앱이 포 그라운드에 있습니다.
    • IME
    • 벽지 서비스
    • 알림 리스너
    • 음성 또는 문자 서비스

이러한 조건 중 어느 것도 해당되지 않으면 앱이 백그라운드에있는 것으로 간주됩니다.


0

이 오래된 게시물에 대한 또 다른 해결책 (도움이되는 사람들을위한) :


<application android:name=".BaseApplication" ... >

public class BaseApplication extends Application {

    private class Status {
        public boolean isVisible = true;
        public boolean isFocused = true;
    }

    private Map<Activity, Status> activities;

    @Override
    public void onCreate() {
        activities = new HashMap<Activity, Status>();
        super.onCreate();
    }

    private boolean hasVisibleActivity() {
        for (Status status : activities.values())
            if (status.isVisible)
                return true;
        return false;
    }

    private boolean hasFocusedActivity() {
        for (Status status : activities.values())
            if (status.isFocused)
                return true;
        return false;
    }

    public void onActivityCreate(Activity activity, boolean isStarting) {
        if (isStarting && activities.isEmpty())
            onApplicationStart();
        activities.put(activity, new Status());
    }

    public void onActivityStart(Activity activity) {
        if (!hasVisibleActivity() && !hasFocusedActivity())
            onApplicationForeground();
        activities.get(activity).isVisible = true;
    }

    public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
        activities.get(activity).isFocused = hasFocus;
    }

    public void onActivityStop(Activity activity, boolean isFinishing) {
        activities.get(activity).isVisible = false;
        if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
            onApplicationBackground();
    }

    public void onActivityDestroy(Activity activity, boolean isFinishing) {
        activities.remove(activity);
        if(isFinishing && activities.isEmpty())
            onApplicationStop();
    }

    private void onApplicationStart() {Log.i(null, "Start");}
    private void onApplicationBackground() {Log.i(null, "Background");}
    private void onApplicationForeground() {Log.i(null, "Foreground");}
    private void onApplicationStop() {Log.i(null, "Stop");}

}

public class MyActivity extends BaseActivity {...}

public class BaseActivity extends Activity {

    private BaseApplication application;

    @Override
    protected void onCreate(Bundle state) {
        application = (BaseApplication) getApplication();
        application.onActivityCreate(this, state == null);
        super.onCreate(state);
    }

    @Override
    protected void onStart() {
        application.onActivityStart(this);
        super.onStart();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        application.onActivityWindowFocusChanged(this, hasFocus);
        super.onWindowFocusChanged(hasFocus);
    }

    @Override
    protected void onStop() {
        application.onActivityStop(this, isFinishing());
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        application.onActivityDestroy(this, isFinishing());
        super.onDestroy();
    }

}

0

onActivityDestroyed 함수의 주석을 참조하십시오.

SDK 대상 버전 14에서 작동 :>

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {

    public static int active = 0;

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());
        active--;
    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());
        active++;
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
        active++;
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
        active--;
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
        active--;

        // if active var here ever becomes zero, the app is closed or in background
        if(active == 0){
            ...
        }

    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
        active++;
    }
}

0

공유 환경 설정을 사용하여 속성을 저장하고 활동의 서비스 바인딩 을 사용하여 속성 을 처리해야합니다. 바인딩 만 사용하는 경우 (startService를 사용하지 않음) 서비스는 포 그라운드에서만 실행되도록 바인딩 할 때 (onResume에 바인딩하고 onPause에 바인딩 해제)에만 서비스를 실행하며 작업하려는 경우 정기적 인 시작 중지 서비스를 사용할 수 있습니다.


0

나는이 질문이 더 분명해야한다고 생각합니다. 언제? 어디? 앱이 백그라운드에있는 경우 확인하려는 특정 상황은 무엇입니까?

방금 내 솔루션을 소개합니다. 내 응용 프로그램 의 모든 활동 방법에서 클래스의
"중요도"필드를 사용 하여이 작업을 수행합니다. "중요도"의 값을 확인하는 방법을 구현하는 다른 활동을 확장 하여 간단히 얻을 수 있습니다 . 코드는 다음과 같습니다.RunningAppProcessInfoonStopBaseActivityonStop

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

@Idolon의 답변에 명시된 권장 솔루션은 아닙니다.
CoolMind

0

이 페이지를 읽는 것이 좋습니다. http://developer.android.com/reference/android/app/Activity.html

즉, 활동이 onStop()호출 된 후에는 더 이상 활동이 표시되지 않습니다 .


3
신청서에 약 10 개의 활동이 있습니다. 따라서 사용자에게 표시되는 것이 없는지 알고 싶습니다. 모든, 나는 전체 내 응용 프로그램이 백그라운드에서 실행되고 있는지 알고 싶다
cppdev

그럼 당신은 모든 10-ish를 추적합니다. 또는 CommonsWare가 제안한대로 수행하려는 작업을 설명하십시오.
Key

3
이것은 정확하지 않습니다. 귀하의 활동은 onStop; 사이 onPause그리고 onStop그건 볼 수 있지만 전경 .
nickgrim

@nickgrim : 무엇이 잘못 되었습니까? 활동이 더 이상 보이지 않습니다onStop() 당신이 쓴 것과 일치 .

@Key : 원래까지 onPause호출 할 때까지 : 최근 편집으로 수정했습니다.
nickgrim

0

getApplicationState (). isInForeground () 사용은 어떻습니까?


0

제 생각에는 많은 답변이 많은 양의 코드를 도입하고 많은 복잡성과 가독성을 가져옵니다.

사람들이 SO Service와 a 사이의 통신 방법을 물으면 Activity일반적으로 LocalBroadcastManager 를 사용하는 것이 좋습니다 .


왜?

글쎄, 문서를 인용함으로써 :

  • 브로드 캐스트하는 데이터가 앱을 떠나지 않으므로 개인 데이터 유출에 대해 걱정할 필요가 없습니다.

  • 다른 응용 프로그램에서 이러한 브로드 캐스트를 앱으로 보낼 수 없으므로 악용 할 수있는 보안 허점에 대해 걱정할 필요가 없습니다.

  • 시스템을 통해 글로벌 브로드 캐스트를 전송하는 것보다 효율적입니다.

문서에 없습니다.

  • 외부 라이브러리가 필요하지 않습니다
  • 코드는 최소한입니다
  • 구현하고 이해하는 것이 빠릅니다.
  • 맞춤형 자체 구현 콜백 / 초 단일 / 프로세스 내 패턴 없음 ...
  • 아니 강한 참조Activity, Application...

기술

따라서 Activity현재 전경 에있는 것이 있는지 확인하고 싶습니다 . 당신은 보통 Service또는 Application수업 에서 그렇게합니다 .

즉, Activity객체가 신호를 보내는 사람이됩니다 (켜짐 / 꺼짐). 여러분 Service, 다른 한편으로는,이된다 Receiver.

거기 의 순간은Activity전경이나 배경으로 가고 있는지 알려주 (예 : 6이 아닌 2 개만).

Activity포 그라운드로 갈 때 onResume()메소드가 트리거됩니다 (또한onCreate() ).

(가) 때 Activity뒤쪽에 간다,onPause() 라고합니다.

이것은 당신이 당신 Activity의 신호를 보내야 할 순간입니다Service 상태를 설명 위해 .

여러 경우 Activity의,은 An 기억Activity 이 먼저 백그라운드로 이동하고 다른 하나가 포 그라운드로 들어온 .

따라서 상황은 다음과 같습니다. *

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

Service/는 Application단순히 그 신호 대기를 유지하고 그에 따라 행동 할 것이다.


코드 (TLDR)

귀하는 Service를 구현해야 BroadcastReceiver신호를 수신하기 위해.

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

레지스터 Receiver의를Service::onCreate()

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

등록 해제 Service::onDestroy()

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

이제 귀하 Activity의 상태를 알려야합니다.

Activity::onResume()

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

Activity::onPause()

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

매우 일반적인 상황

개발자 : 내 데이터를 보내고을 Service업데이트하고 싶습니다 Activity. Activity가 전경에 있는지 어떻게 확인 합니까?

일반적으로 Activity전경에 있는지 여부를 확인할 필요가 없습니다. LocalBroadcastManager에서 를 통해 데이터를 보내 십시오 Service. Activity이 켜져 있으면 응답하고 작동합니다.

이 매우 일반적인 상황에서는 Service발신자가되고 Activity구현은을 구현합니다 BroadcastReceiver.

따라서에을 만드 Receiver십시오 Activity. 에 등록하고 등록을 onResume()취소하십시오 onPause(). 다른 수명주기 방법을 사용할 필요가 없습니다 .

Receiver동작을 정의하십시오 onReceive()(ListView 업데이트,이 작업을 수행하십시오 ...).

이렇게 Activity하면 전경에있는 경우에만 청취하고 뒤쪽에 있거나 파괴 된 경우 아무 일도 일어나지 않습니다.

여러 개의 경우 켜져있는 ActivityActivity하나라도 응답합니다 (또한 구현 한 경우 Receiver).

모두 배경에 있으면 아무도 응답하지 않고 신호가 손실됩니다.

신호 ID를 지정하여 Servicevia 에서 데이터를 전송하십시오 Intent(위 코드 참조).


  • 다중 창 지원 제외 . 까다로울 수 있습니다 (필요한 경우 테스트하십시오) ...

0
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

특정 활동이 진행 중인지 여부와 응용 프로그램에 직접 액세스 할 수없는 SDK 인 경우 특정 사례에 맞는 답변이 없습니다. 나에게 새로운 대화 메시지에 대한 푸시 알림을받은 백그라운드 스레드에 있었고 채팅 화면이 전경에없는 경우에만 시스템 알림을 표시하려고합니다.

ActivityLifecycleCallbacks다른 답변에서 권장 되는 것을 사용하여 MyActivityForeground 에 있는지 여부에 대한 논리를 포함하는 작은 유틸리티 클래스를 만들었습니다 .

class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {

private var isMyActivityInForeground = false

init {
    (context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}

fun isMyActivityForeground() = isMyActivityInForeground

override fun onActivityPaused(activity: Activity?) {
    if (activity is MyActivity) {
        isMyActivityInForeground = false
    }
}

override fun onActivityResumed(activity: Activity?) {
    if (activity is MyActivity) {
        isMyActivityInForeground = true
    }
}

}


-1

내 활동 onResume 및 onPause에서 isVisible 부울을 SharedPrefences에 씁니다.

    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sharedPrefs.edit();
    editor.putBoolean("visible", false);
    editor.commit();

필요할 때 다른 곳에서 읽어보십시오.

    // Show a Toast Notification if App is not visible (ie in background. Not running, etc) 
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    if(!sharedPrefs.getBoolean("visible", true)){...}

아마 우아하지는 않지만 그것은 나를 위해 작동합니다 ...


-1

대답하기에는 너무 늦을 수도 있지만 누군가가 방문하면 여기에 제안하는 해결책이 있습니다. 앱이 백그라운드에 있거나 전경에 오는 상태를 알고 싶어하는 이유는 많을 수 있습니다. 사용자가 BG에있을 때 토스트 및 알림을 표시합니다. 2. 설문 조사, 다시 그리기 등과 같이 사용자가 BG에서 처음 왔을 때 일부 작업을 수행하려면

Idolon 등의 솔루션은 첫 번째 부분을 처리하지만 두 번째 부분은 처리하지 않습니다. 앱에 여러 액티비티가 있고 사용자가 액티비티간에 전환하는 경우 두 번째 액티비티에있을 때 표시되는 플래그는 false입니다. 따라서 결정적으로 사용할 수 없습니다.

나는 CommonsWare가 제안한 것을 수행했다. "서비스가 가시적 인 활동이 없다고 판단하고 일정 시간 동안 그런 식으로 유지 되면 다음 논리적 중지 지점에서 데이터 전송을 중지하십시오."

굵은 선은 중요하며 두 번째 항목을 달성하는 데 사용할 수 있습니다. 그래서 내가하는 일은 일단 onActivityPaused ()를 얻고 가시성을 직접 false로 변경하지 않고 대신 3 초의 타이머 (다음 액티비티가 시작되어야하는 최대 값)를 가지며 onActivityResumed ( ) 다음 3 초 후에 호출하고 표시를 false로 변경하십시오. 마찬가지로 onActivityResumed ()에서 타이머가 있으면 취소합니다. 요약하면 보이는 것은 isAppInBackground입니다.

코드를 복사하여 붙여 넣을 수 없습니다 ...


-3

다른 방법으로이 작업을 수행하는 것이 좋습니다.

프로그램이 시작되는 동안 시작 화면을 표시하고 싶습니다. 이미 백엔드에서 실행중인 경우 표시하지 마십시오.

응용 프로그램은 현재 시간을 특정 파일에 지속적으로 쓸 수 있습니다. 응용 프로그램이 시작되는 동안 current_time-last_time> 최근 시간을 쓰기 위해 지정한 시간 범위 인 경우 마지막 타임 스탬프를 확인하십시오. 이는 시스템 또는 사용자가 응용 프로그램을 종료했음을 의미합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.