programing

Android 앱이 백그라운드로 이동했다가 다시 백그라운드로 이동할 때 탐지하는 방법

mailnote 2023. 6. 10. 09:38
반응형

Android 앱이 백그라운드로 이동했다가 다시 백그라운드로 이동할 때 탐지하는 방법

나는 시간이 좀 지난 후에 다시 전면에 나오면 특정한 것을 하는 앱을 쓰려고 합니다.앱이 백그라운드로 전송되거나 포그라운드로 이동될 때 감지할 수 있는 방법이 있습니까?

2018: Android는 라이프사이클 구성요소를 통해 기본적으로 이를 지원합니다.

2018년 3월 업데이트:이제 더 나은 해결책이 있습니다.프로세스 수명 주기 소유자를 참조하십시오.새로운 아키텍처 구성 요소 1.1.0(현재 최신 버전)을 사용해야 하지만 이를 위해 특별히 설계되었습니다.

답변에는 간단한 샘플이 제공되지만 는 샘플 앱과 블로그 게시물을 작성했습니다.

제가 2014년에 이 글을 쓴 이후로, 다른 해결책들이 생겨났습니다.일부는 작동했고, 일부는 작동하는 것으로 생각되었지만 결함이 있었습니다(내 것 포함). 그리고 공동체로서 우리(Android)는 결과를 감수하는 법을 배우고 특별한 경우에 대한 해결책을 썼습니다.

코드 조각 하나가 여러분이 찾고 있는 해결책이라고 가정하지 마세요. 그럴 가능성은 거의 없습니다. 더 나은 것은, 그것이 무엇을 하고 왜 그것을 하는지 이해하려고 노력하는 것입니다.

MemoryBoss수업은 여기 적혀있는 것처럼 제가 실제로 사용한 적이 없습니다. 그것은 우연히 작동한 가짜 코드의 일부일 뿐입니다.

새 아키텍처 구성 요소(특히 super old 아피스를 대상으로 하는 경우)를 사용하지 않을 만한 타당한 이유가 없는 한, 계속 사용하십시오.그들은 완벽과는 거리가 멀지만, 둘 다 그렇지 않았습니다.ComponentCallbacks2.

업데이트 / 참고 사항(2015년 11월):사람들은 두 가지 의견을 말해왔습니다, 첫 번째는.>=대신 사용해야 합니다.==정확한 값을 확인하면 안 된다고 문서에 명시되어 있기 때문입니다.대부분의 경우 이 방법은 괜찮지만 앱이 백그라운드에서 실행될 때만 사용하는 경우에는 ==를 사용하고 다른 솔루션(예: 활동 라이프사이클 콜백)과 결합해야 합니다. 그렇지 않으면 원하는 효과를 얻지 못할 수도 있습니다.예를 들어 백그라운드로 이동할 때(예: 익숙한 경우 1Password) 암호 화면으로 앱을 잠그려면 메모리가 부족하고 갑자기 테스트를 수행할 경우 실수로 앱을 잠글 수 있습니다.>= TRIM_MEMORY를 트리거할 것이기 때문입니다.LOW MEMORY전화를 하면 당신 것보다 더 높습니다.따라서 어떻게/무엇을 테스트하는지 주의해야 합니다.

게다가, 어떤 사람들은 당신이 돌아왔을 때 탐지하는 방법에 대해 물었습니다.

제가 생각할 수 있는 가장 간단한 방법은 아래에 설명되어 있지만, 몇몇 사람들은 그것에 익숙하지 않기 때문에, 저는 여기에 의사 코드를 추가하고 있습니다.당신이 가지고 있다고 가정하면YourApplication 리고그고.MemoryBoss에서, 용자사래.class BaseActivity extends Activity(이 파일이 없는 경우 파일을 만들어야 합니다.

@Override
protected void onStart() {
    super.onStart();

    if (mApplication.wasInBackground()) {
        // HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
        mApplication.setWasInBackground(false);
    }
}

시작할 때는 대화 상자가 활동을 일시 중지할 수 있으므로 전체 화면 대화 상자를 표시하는 것이 전부라면 앱이 "백그라운드로 이동했다"고 생각하지 않도록 권장하지만 마일리지는 달라질 수 있습니다.

그리고 그게 다에요.if 블록의 코드는 다른 활동, 즉 새로운 활동으로 이동하더라도 한 번만 실행됩니다.extends BaseActivity가할 것입니다.wasInBackground이라false호출되고 플래그가 다시 true로 설정될 때까지 코드를 실행하지 않습니다.

업데이트 / 참고(2015년 4월):이 코드에 대한 모든 복사 및 붙여넣기 작업을 수행하기 전에 100% 신뢰할 수 없으며 최상의 결과를 얻으려면 다른 방법과 결합해야 하는 몇 가지 사례를 발견했습니다.특히, 두 가지 알려진 사례가 있습니다.onTrimMemory콜백이 실행되는 것은 보장되지 않습니다.

  1. 앱이 표시되는 동안 전화기가 화면을 잠그는 경우(예: nn분 후 장치가 잠기는 경우) 잠금 화면이 바로 위에 있지만 앱이 여전히 "실행 중"이기 때문에 이 콜백이 호출되지 않습니다(또는 항상 호출되지는 않습니다).

  2. 장치의 메모리가 상대적으로 부족하고 메모리 스트레스가 심한 경우 운영 체제는 이 호출을 무시하고 더 중요한 수준으로 바로 이동하는 것 같습니다.

이제 앱이 언제 백그라운드에서 실행되었는지 아는 것이 얼마나 중요한지에 따라 이 솔루션을 활동 라이프사이클 및 기타 활동을 추적하는 것과 함께 확장할 필요가 있을 수도 있고 그렇지 않을 수도 있습니다.

위 내용만 참고하시고 좋은 QA팀 되세요 ;)

업데이트 종료

늦을지도 모르지만, 아이스크림 샌드위치(API 14) 이상에서는 믿을 만한 방법이 있습니다.

앱에 더 이상 표시되는 UI가 없을 때 콜백이 트리거되는 것으로 나타났습니다.사용자 정의 클래스에서 구현할 수 있는 콜백을 ComponentCallback2(예, 2개 포함)라고 합니다.본 콜백은 API Level 14(Ice Cream Sandwich) 이상에서만 이용 가능합니다.

기본적으로 다음과 같은 방법을 사용할 수 있습니다.

public abstract void onTrimMemory (int level)

레벨은 구체적으로 20 이상입니다.

public static final int TRIM_MEMORY_UI_HIDDEN

저는 이것을 테스트해왔고 항상 작동합니다. 레벨 20은 더 이상 앱이 표시되지 않기 때문에 일부 리소스를 릴리스하기를 원할 수 있는 "제안"이기 때문입니다.

공식 문서 인용하기

onTrimMemory(int)에 대한 수준: 프로세스가 사용자 인터페이스를 표시해 왔으나 더 이상 표시하지 않습니다.메모리를 더 잘 관리할 수 있도록 UI가 포함된 큰 할당을 이 시점에서 해제해야 합니다.

물론 실제로 이 기능을 구현하여 지정된 시간 내에 사용되지 않은 메모리 제거, 사용하지 않은 일부 컬렉션 지우기 등을 수행해야 합니다.가능성은 무궁무진합니다(다른 가능한 더 중요한 수준은 공식 문서 참조).

하지만, 흥미로운 것은, 그 운영체제가 당신에게 말합니다: 이봐요, 당신의 앱은 백그라운드로 갔어요!

그게 바로 당신이 애초에 알고 싶어했던 것입니다.

당신은 언제 돌아왔는지 어떻게 결정합니까?

쉬운 일입니다. "기본 활동"이 있으므로 onResume()를 사용하여 복귀 사실에 플래그를 지정할 수 있습니다.왜냐하면 당신이 돌아오지 않았다고 말하는 유일한 시간은 당신이 실제로 위의 전화를 받았을 때이기 때문입니다.onTrimMemory방법.

그건 효과가 있다.당신은 잘못된 긍정을 얻지 못합니다.활동이 재개되면 100% 복귀합니다.사용자가 다시 뒤로 이동하면 다른 사용자가 나타납니다.onTrimMemory()콜.콜.

활동(또는 사용자 정의 클래스)을 구독해야 합니다.

항상 수신을 보장하는 가장 쉬운 방법은 다음과 같은 간단한 클래스를 만드는 것입니다.

public class MemoryBoss 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) {
            // We're in the Background
        }
        // you might as well implement some memory cleanup here and be a nice Android dev.
    }
}

이를 사용하려면 애플리케이션 구현에서 다음과 같은 작업을 수행합니다.

MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
   super.onCreate();
   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
      mMemoryBoss = new MemoryBoss();
      registerComponentCallbacks(mMemoryBoss);
   } 
}

Interface추할수있다니습을 할 수 .else 거기까까지if을 구현합니다.ComponentCallbacks 14. (2를 사용하지 않음) API 14에서 됩니다.해당 콜백에는 다음 항목만 포함됩니다.onLowMemory()백그라운드로 이동할 때 메서드가 호출되지 않지만 메모리를 트리밍하는 데 사용해야 합니다.

이제 앱을 실행하고 홈을 누릅니다.당신의.onTrimMemory(final int level)메서드를 호출해야 합니다(예: 로깅 추가).

마지막 단계는 콜백에서 등록을 취소하는 것입니다.아마도 가장 좋은 장소는onTerminate()앱의 메서드는 실제 장치에서 호출되지 않습니다.

/**
 * This method is for use in emulated process environments.  It will
 * never be called on a production Android device, where processes are
 * removed by simply killing them; no user code (including this callback)
 * is executed when doing so.
 */

따라서 더 이상 등록을 원하지 않는 상황이 아니라면 OS 수준에서 프로세스가 중단되고 있기 때문에 안전하게 무시할 수 있습니다.

어떤 시점에서 등록을 취소하기로 결정한 경우(예를 들어 앱이 정리 및 종료할 수 있는 종료 메커니즘을 제공하는 경우) 다음 작업을 수행할 수 있습니다.

unregisterComponentCallbacks(mMemoryBoss);

그리고 이것이 마지막입니다.

제가 이 문제를 해결한 방법은 다음과 같습니다.활동 전환 사이의 시간 참조를 사용하면 앱이 "배경"되었는지 여부에 대한 충분한 증거를 제공할 가능성이 높다는 전제 하에 작동합니다.

먼저 안드로이드.앱을 사용해봤습니다.Timer, TimerTask, 한 활동에서 다른 활동으로 전환하는 데 합리적으로 걸릴 수 있는 최대 시간(밀리초)을 나타내는 상수(2초 값으로 이동) 및 앱이 "백그라운드"인지 여부를 나타내는 부울이 있는 애플리케이션 인스턴스(MyApplication이라고 부울):

public class MyApplication extends Application {

    private Timer mActivityTransitionTimer;
    private TimerTask mActivityTransitionTimerTask;
    public boolean wasInBackground;
    private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
    ...

이 애플리케이션은 또한 타이머/작업을 시작 및 중지하는 두 가지 방법을 제공합니다.

public void startActivityTransitionTimer() {
    this.mActivityTransitionTimer = new Timer();
    this.mActivityTransitionTimerTask = new TimerTask() {
        public void run() {
            MyApplication.this.wasInBackground = true;
        }
    };

    this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
                                           MAX_ACTIVITY_TRANSITION_TIME_MS);
}

public void stopActivityTransitionTimer() {
    if (this.mActivityTransitionTimerTask != null) {
        this.mActivityTransitionTimerTask.cancel();
    }

    if (this.mActivityTransitionTimer != null) {
        this.mActivityTransitionTimer.cancel();
    }

    this.wasInBackground = false;
}

이 솔루션의 마지막 부분은 모든 활동의 onResume() 및 pause() 이벤트 또는 모든 구체적인 활동이 상속되는 기본 활동에서 이러한 각 메서드에 호출을 추가하는 것입니다.

@Override
public void onResume()
{
    super.onResume();

    MyApplication myApp = (MyApplication)this.getApplication();
    if (myApp.wasInBackground)
    {
        //Do specific came-here-from-background code
    }

    myApp.stopActivityTransitionTimer();
}

@Override
public void onPause()
{
    super.onPause();
    ((MyApplication)this.getApplication()).startActivityTransitionTimer();
}

따라서 사용자가 단순히 앱의 활동 사이를 이동하는 경우, 떠나는 활동의 onPause()가 타이머를 시작하지만, 거의 즉시 입력되는 새 활동이 최대 전환 시간에 도달하기 전에 타이머를 취소합니다.그리고 InBackground도 거짓일 것입니다.

반면에 Launcher, Device Wake, End Phone Call 등에서 활동이 포그라운드로 오면 이 이벤트 전에 실행된 타이머 작업이 true로 설정되어 있을 가능성이 높습니다.

2021년 11월 업데이트

실제 설정은 다음과 같습니다.

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
    }
}

class AppLifecycleListener : DefaultLifecycleObserver {

    override fun onStart(owner: LifecycleOwner) { // app moved to foreground
    }

    override fun onStop(owner: LifecycleOwner) { // app moved to background
    }
}

종속성

implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"

원답

ProcessLifecycleOwner 또한 유망한 해결책인 것 같습니다.

Process 합니다.ON_START,ON_RESUME첫 번째 활동이 이러한 이벤트를 통해 이동할 때 이벤트. ON_PAUSE,ON_STOP이벤트는 마지막 활동이 이벤트를 통과한 후 지연되어 발송됩니다.이 지연은 그것을 보장하기에 충분히 깁니다.ProcessLifecycleOwner에서는 구성 변경으로 인해 활동이 삭제되고 다시 생성된 경우 이벤트를 보내지 않습니다.

구현은 다음과 같이 단순할 수 있습니다.

class AppLifecycleListener : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onMoveToForeground() { // app moved to foreground
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onMoveToBackground() { // app moved to background
    }
}

// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())

소스 코드에 따르면 현재 지연 값은700ms.

이 하려면 또한이사려면하용이 합니다.dependencies:

implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"

편집: 새로운 아키텍처 구성 요소는 다음과 같은 이점을 제공했습니다. ProcessLifeCycleOwner, @vokilam의 답변 참조


Google I/O 토크에 따르면 실제 솔루션은 다음과 같습니다.

class YourApplication : Application() {

  override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(AppLifecycleTracker())
  }

}


class AppLifecycleTracker : Application.ActivityLifecycleCallbacks  {

  private var numStarted = 0

  override fun onActivityStarted(activity: Activity?) {
    if (numStarted == 0) {
      // app went to foreground
    }
    numStarted++
  }

  override fun onActivityStopped(activity: Activity?) {
    numStarted--
    if (numStarted == 0) {
      // app went to background
    }
  }

}

네. 여기 이상한 해결책이 너무 많아서 이 간단한 해결책이 효과가 있다는 것을 믿기 어렵다는 것을 알고 있습니다.

하지만 희망은 있습니다.

onPause()그리고.onResume()메소드는 응용 프로그램이 백그라운드 및 포그라운드로 다시 이동할 때 호출됩니다.그러나 응용 프로그램이 처음 시작될 때와 제거되기 전에 호출되기도 합니다.활동에서 더 많은 내용을 읽을 수 있습니다.

또는인 접근법은, 이 적이 .onWindowFocusChanged그리고.onStop.

자세한 내용은 여기 Android에서 확인하십시오. 실행 중인 작업이나 실행 인 앱 프로세스가져오지 않고 Android 앱이 백그라운드로 이동했다가 다시 백그라운드로 돌아오는 시기를 감지하는 솔루션입니다.

Martin Marconcinis 답변을 기반으로 합니다(감사합니다!)저는 마침내 신뢰할 수 있는 (그리고 매우 간단한) 해결책을 찾았습니다.

public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
    private static boolean isInBackground = false;

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

    @Override
    public void onActivityStarted(Activity activity) {
    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){
            Log.d(TAG, "app went to foreground");
            isInBackground = false;
        }
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

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

    @Override
    public void onActivityDestroyed(Activity activity) {
    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {
    }

    @Override
    public void onLowMemory() {
    }

    @Override
    public void onTrimMemory(int i) {
        if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
            Log.d(TAG, "app went to background");
            isInBackground = true;
        }
    }
}

그런 다음 응용프로그램 클래스의 onCreate()에 추가합니다.

public class MyApp extends android.app.Application {

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

        ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
        registerActivityLifecycleCallbacks(handler);
        registerComponentCallbacks(handler);

    }

}

우리는 이 방법을 사용합니다.작동하기에는 너무 간단해 보이지만, 앱에서 테스트를 잘 받았으며 실제로 "홈" 버튼, "돌아가기" 버튼 또는 화면 잠금 후에 홈 화면으로 이동하는 것을 포함하여 모든 경우에서 놀라울 정도로 잘 작동합니다.한번 해보라구요.

아이디어는, 전면적으로 안드로이드가 항상 이전 활동을 중단하기 직전에 새로운 활동을 시작한다는 것입니다.그것은 보장되지 않지만, 그렇게 작동합니다. BTW, Flurry는 동일한 논리를 사용하는 것 같습니다(추측일 뿐, 제가 확인하지는 않았지만 동일한 이벤트에서 후크됩니다).

public abstract class BaseActivity extends Activity {

    private static int sessionDepth = 0;

    @Override
    protected void onStart() {
        super.onStart();       
        sessionDepth++;
        if(sessionDepth == 1){
        //app came to foreground;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (sessionDepth > 0)
            sessionDepth--;
        if (sessionDepth == 0) {
            // app went to background
        }
    }

}

편집: 코멘트에 따라 코드의 최신 버전에서는 onStart()로 이동했습니다.또한, 제 첫 게시물에서 누락된 슈퍼 콜을 추가합니다. 왜냐하면 이것은 작동 코드라기보다는 개념에 가까웠기 때문입니다.

앱이 탭 모음 위젯과 같이 여러 개의 활동 및/또는 쌓인 활동으로 구성된 경우 일시 중지() 및 재개()에 대해 재정의할 수 없습니다.즉, 새 활동을 시작할 때 현재 활동은 새 활동이 생성되기 전에 일시 중지됩니다.활동을 완료할 때("뒤로" 단추 사용)에도 동일하게 적용됩니다.

원하는 대로 작동하는 두 가지 방법을 찾았습니다.

첫 번째 방법은 GET_TASKS 권한이 필요하며 패키지 이름을 비교하여 장치에서 실행 중인 최상위 활동이 응용 프로그램에 속하는지 확인하는 간단한 방법으로 구성됩니다.

private boolean isApplicationBroughtToBackground() {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            return true;
        }
    }

    return false;
}

이 방법은 Droid-Fu(현재 점화라고 함) 프레임워크에서 발견되었습니다.

제가 직접 구현한 두 번째 방법은 GET_TASKS 권한이 필요하지 않아 좋습니다.대신에 그것은 구현하기가 조금 더 복잡합니다.

기본 응용 프로그램 클래스에는 응용 프로그램에서 실행 중인 활동 수를 추적하는 변수가 있습니다.각 활동에 대해 계속()에서 변수를 늘리고 일시 중지()에서 변수를 줄입니다.

실행 중인 작업 수가 0에 도달하면 다음 조건이 충족되면 응용 프로그램이 백그라운드로 전환됩니다.

  • 일시 중지 중인 활동이 완료되지 않았습니다("뒤로" 단추 사용).메서드 활동을 사용하여 이 작업을 수행할 수 있습니다.isFinishing()
  • 새 활동(동일한 패키지 이름)이 시작되고 있지 않습니다.startActivity() 메서드를 재정의하여 이를 나타내는 변수를 설정한 다음 활동이 생성/재개될 때 실행되는 마지막 메서드인 PostResume()에서 재설정할 수 있습니다.

응용프로그램이 백그라운드에서 삭제된 것을 탐지할 수 있는 경우 응용프로그램이 포그라운드로 다시 이동할 때도 쉽게 탐지할 수 있습니다.

확장할 클래스 만들기Application그런다음오버드방사법수용다있니습할을이라,▁its▁method다▁then▁use니▁override를 사용할 수 있습니다.onTrimMemory().

응용 프로그램이 백그라운드로 이동했는지 여부를 탐지하기 위해 다음을 사용합니다.

 @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
            // Get called every-time when application went to background.
        } 
        else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
        }
    }

User LeaveHint에서 사용하는 것을 고려합니다.앱이 백그라운드로 이동할 때만 호출됩니다.OnPause는 다른 이유로 호출될 수 있기 때문에 처리해야 할 코너 케이스가 있습니다. 예를 들어, 사용자가 앱에서 설정 페이지와 같은 다른 활동을 열 경우,당신의 주요 활동의 onPause 메서드는 그것들이 당신의 앱에 여전히 있더라도 호출될 것입니다. 당신이 요청하는 것을 하는 onUserLeaveHint 콜백을 사용할 수 있을 때 무엇이 들어가는지 추적하는 것은 버그로 이어질 것입니다.

on User LeaveHint가 호출되면 boolean inBackground 플래그를 true로 설정할 수 있습니다.onResume이 호출되면 inBackground 플래그가 설정된 경우에만 사용자가 전경으로 돌아왔다고 가정합니다.이는 사용자가 설정 메뉴에 있을 뿐 앱을 떠나지 않은 경우에도 onResume이 기본 활동에 대해 호출되기 때문입니다.

사용자가 설정 화면에서 홈 버튼을 누르면 User LeaveHint가 설정 작업에 호출되고, 사용자가 설정 작업을 다시 시작하면 설정 작업에 호출됩니다.기본 활동에 이 탐지 코드만 있으면 이 사용 사례를 놓치게 됩니다.코드를 복제하지 않고 모든 활동에 이 코드를 사용하려면 활동을 확장하는 추상 활동 클래스를 가지고 공통 코드를 넣으십시오.그러면 각 활동이 이 추상적인 활동을 확장할 수 있습니다.

예:

public abstract AbstractActivity extends Activity {
    private static boolean inBackground = false;

    @Override
    public void onResume() {
        if (inBackground) {
            // You just came from the background
            inBackground = false;
        }
        else {
            // You just returned from another activity within your own app
        }
    }

    @Override
    public void onUserLeaveHint() {
        inBackground = true;
    }
}

public abstract MainActivity extends AbstractActivity {
    ...
}

public abstract SettingsActivity extends AbstractActivity {
    ...
}

Android.arch.lifecycle 패키지는 라이프사이클 인식 구성 요소를 구축할 수 있는 클래스 및 인터페이스를 제공합니다.

응용 프로그램은 LifecycleObserver 인터페이스를 구현해야 합니다.

public class MyApplication extends Application implements LifecycleObserver {

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

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

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

이렇게 하려면 build.gradle 파일에 다음과 같은 종속성을 추가해야 합니다.

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

Google에서 권장하는 대로 라이프사이클 작업 방법에서 실행되는 코드를 최소화해야 합니다.

일반적인 패턴은 활동 및 단편의 라이프사이클 방법에서 종속 구성요소의 작업을 구현하는 것입니다.그러나 이러한 패턴은 코드의 잘못된 구성과 오류의 확산을 초래합니다.수명 주기 인식 구성 요소를 사용하면 종속 구성 요소의 코드를 수명 주기 방법에서 구성 요소 자체로 이동할 수 있습니다.

자세한 내용은 여기에서 확인할 수 있습니다. https://developer.android.com/topic/libraries/architecture/lifecycle

활동 라이프사이클 콜백은 관심을 가질 수 있지만 문서화되어 있지 않습니다.

그러나 registerActivityLifecycleCallback()을 호출하면 언제 활동이 생성되거나 삭제되는지 등에 대한 콜백을 받을 수 있습니다.활동에 대해 getComponentName()을 호출할 수 있습니다.

응용프로그램에서 콜백을 추가하고 다음과 같은 방법으로 루트 활동을 확인합니다.

@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
        @Override
        public void onActivityStopped(Activity activity) {
        }

        @Override
        public void onActivityStarted(Activity activity) {
        }

        @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) {
            if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
                Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
                loadDefaults();
            }
        }
    });
}

프로세스 수명 주기 소유자를 사용하여 수명 주기 관찰자를 연결할 수 있습니다.

  public class ForegroundLifecycleObserver implements LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onAppCreated() {
        Timber.d("onAppCreated() called");
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppStarted() {
        Timber.d("onAppStarted() called");
    }

    @OnLifecycleEvent(Event.ON_RESUME)
    public void onAppResumed() {
        Timber.d("onAppResumed() called");
    }

    @OnLifecycleEvent(Event.ON_PAUSE)
    public void onAppPaused() {
        Timber.d("onAppPaused() called");
    }

    @OnLifecycleEvent(Event.ON_STOP)
    public void onAppStopped() {
        Timber.d("onAppStopped() called");
    }
}

다음에 다에음그에.onCreate()애플리케이션 클래스에서 다음과 같이 부릅니다.

ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());

은 이으로당의사포수있것다입의 를 할 수 .ON_PAUSE그리고.ON_STOP백그라운드에서 실행되는 응용 프로그램의 경우.

Github app-forground-background-listen에 대한 프로젝트를 만들었습니다.

응용프로그램의 모든 활동에 대한 기본 활동을 만듭니다.

public class BaseActivity extends Activity {

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

    public static boolean isAppInFg = false;
    public static boolean isScrInFg = false;
    public static boolean isChangeScrFg = false;

    @Override
    protected void onStart() {
        if (!isAppInFg) {
            isAppInFg = true;
            isChangeScrFg = false;
            onAppStart();
        }
        else {
            isChangeScrFg = true;
        }
        isScrInFg = true;

        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (!isScrInFg || !isChangeScrFg) {
            isAppInFg = false;
            onAppPause();
        }
        isScrInFg = false;
    }

    public void onAppStart() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in foreground",    Toast.LENGTH_LONG).show();

        // Your code
    }

    public void onAppPause() {

        // Remove this toast
        Toast.makeText(getApplicationContext(), "App in background",  Toast.LENGTH_LONG).show();

        // Your code
    }
}

이제 이 기본 활동을 기본 활동이 확장되는 것처럼 모든 활동의 수퍼 클래스로 사용하면 응용 프로그램을 시작할 때 onAppStart가 호출되고 응용 프로그램이 화면에서 백그라운드로 이동할 때 onAppPause()가 호출됩니다.

프로세스 라이프사이클 소유자를 사용하면 매우 간단합니다.

이러한 종속성 추가

implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"

코틀린에서:

class ForegroundBackgroundListener : LifecycleObserver {


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun startSomething() {
        Log.v("ProcessLog", "APP IS ON FOREGROUND")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopSomething() {
        Log.v("ProcessLog", "APP IS IN BACKGROUND")
    }
}

그런 다음 기본 활동에서:

override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner.get()
                .lifecycle
                .addObserver(
                        ForegroundBackgroundListener()
                                .also { appObserver = it })
    }

이 주제에 대한 제 기사를 참조하십시오. https://medium.com/ @egek92/방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법-방법

전체 응용프로그램이 백그라운드/포그라운드로 전환되는 시점을 알려주는 간단한 라이프사이클 방법은 없습니다.

나는 이것을 간단한 방법으로 해왔습니다.아래 지침에 따라 응용 프로그램 배경/포그라운드 단계를 탐지합니다.

약간의 해결책만 있으면 가능합니다.여기서 활동 라이프사이클 콜백이 구조에 참여합니다.제가 단계별로 걸겠습니다.

  1. 먼저 Android.app을 확장하는 클래스를 만듭니다.ActivityLifecycleCallbacks 인터페이스를 적용하고 구현합니다.Application.onCreate()에서 콜백을 등록합니다.

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
    
  2. "하십시오.<application android:name=".App".

  3. 앱이 포그라운드에 있을 때 시작된 상태에 하나 이상의 활동이 있고 앱이 백그라운드에 있을 때 시작된 상태에 있는 활동이 없습니다.

    "App" 클래스에서 아래와 같이 변수 2개를 선언합니다.

    private int activityReferences = 0;
    private boolean isActivityChangingConfigurations = false;
    

    activityReferences시작된 상태의 활동 수를 유지합니다. isActivityChangingConfigurations는 현재 활동이 방향 스위치처럼 구성 변경을 겪고 있는지 여부를 나타내는 플래그입니다.

  4. 다음 코드를 사용하여 앱이 전경인지 감지할 수 있습니다.

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
    
  5. 앱이 백그라운드로 실행되는지 탐지하는 방법입니다.

    @Override
    public void onActivityStopped(Activity activity) {
        isActivityChangingConfigurations = activity.isChangingConfigurations();
        if (--activityReferences == 0 && !isActivityChangingConfigurations) {
            // App enters background
        }
    }
    

작동 방식:

이는 라이프사이클 방법을 순서대로 호출하는 방식으로 수행된 작은 속임수입니다.시나리오를 살펴보겠습니다.

사용자가 앱을 실행하고 실행기 활동 A가 실행된다고 가정합니다.라이프사이클 통화는 다음과 같습니다.

A.생성 시()

A. on Start()(+activityReferences == 1)(어플리케이션 포그라운드)

A.재개 시()

이제 활동 A가 활동 B를 시작합니다.

A.일시 중지()

B.생성 시()

B.on Start()(+활동 참조 == 2)

B.재개 시()

A. onStop()(--activityReferences == 1)

그런 다음 사용자가 활동 B에서 다시 탐색합니다.

B.일시 중지()

A. on Start()(+활동 참조 == 2)

A.재개 시()

B.onStop()(--activityReferences == 1)

B.파괴 시()

그런 다음 사용자가 홈 버튼을 누릅니다.

A.일시 중지()

A. onStop()(--activityReferences == 0)(어플리케이션이 백그라운드로 들어갑니다)

버튼 홈는 사서자뒤에참 가▁in▁bere참는이 됩니다.0따라서 백그라운드로 진입하는 앱으로 탐지할 수 있습니다.

그럼, 어떤 역할을 해야 할까요?isActivityChangingConfigurations위 시나리오에서 활동 B가 방향을 변경한다고 가정합니다."Callback"입니다.

B.일시 중지()

B.onStop()(--activityReferences == 0)(어플리케이션이 백그라운드로 입력됩니까??)

B.파괴 시()

B.생성 시()

B.onStart()(+activityReferences == 1)(애플리케이션이 포그라운드에 진입합니까??)

B.재개 시()

그래서 우리는 추가적인 검사를 받고 있습니다.isActivityChangingConfigurations활동이 구성 변경을 거치는 시나리오를 방지합니다.

사용할 수 있는 항목:

다시 시작 시 보호된 void()

새 시작과 다시 시작 사이에 차이가 있습니다.

여기에 이미지 설명 입력

저는 전경을 입력하든 배경을 입력하든 응용 프로그램을 감지할 수 있는 좋은 방법을 찾았습니다.여기 제 코드가 있습니다.이것이 도움이 되길 바랍니다.

/**
 * Custom Application which can detect application state of whether it enter
 * background or enter foreground.
 *
 * @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
 */
 public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {

public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;

private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;

private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;

@Override
public void onCreate() {
    super.onCreate();
    mCurrentState = STATE_UNKNOWN;
    registerActivityLifecycleCallbacks(this);
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    // mCurrentState = STATE_CREATED;
}

@Override
public void onActivityStarted(Activity activity) {
    if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
        if (mStateFlag == FLAG_STATE_BACKGROUND) {
            applicationWillEnterForeground();
            mStateFlag = FLAG_STATE_FOREGROUND;
        }
    }
    mCurrentState = STATE_STARTED;

}

@Override
public void onActivityResumed(Activity activity) {
    mCurrentState = STATE_RESUMED;

}

@Override
public void onActivityPaused(Activity activity) {
    mCurrentState = STATE_PAUSED;

}

@Override
public void onActivityStopped(Activity activity) {
    mCurrentState = STATE_STOPPED;

}

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

}

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

@Override
public void onTrimMemory(int level) {
    super.onTrimMemory(level);
    if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidEnterBackground();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
        if (mStateFlag == FLAG_STATE_FOREGROUND) {
            applicationDidDestroyed();
            mStateFlag = FLAG_STATE_BACKGROUND;
        }
    }
}

/**
 * The method be called when the application been destroyed. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidDestroyed();

/**
 * The method be called when the application enter background. But when the
 * device screen off,this method will not invoked.
 */
protected abstract void applicationDidEnterBackground();

/**
 * The method be called when the application enter foreground.
 */
protected abstract void applicationWillEnterForeground();

}

편집 2: 제가 아래에 쓴 것은 실제로 작동하지 않을 것입니다.Google에서 ActivityManager.getRunningTasks() 호출이 포함된 앱을 거부했습니다.설명서에 따르면 이 API는 디버깅 및 개발 목적으로만 사용됩니다.아래 깃허브 프로젝트를 타이머를 사용하는 새로운 방식으로 업데이트할 시간이 나는 대로 이 게시물을 업데이트하겠습니다.

편집 1: 블로그 게시물을 작성하고 간단한 GitHub 저장소를 만들어 정말 쉽게 할 수 있도록 했습니다.

허용된 답변과 최고 수준의 답변은 둘 다 실제로 최선의 접근 방식은 아닙니다.최상위 응답의 isApplicationBrightedToBackground() 구현은 응용프로그램의 기본 활동이 동일한 응용프로그램에 정의된 활동에 종속되는 상황을 처리하지 않지만 다른 Java 패키지를 가지고 있습니다.저는 이 경우에 효과적인 방법을 생각해냈습니다.

Pause()에 호출하면 다른 응용 프로그램이 시작되어 프로그램이 백그라운드로 이동하는지 또는 사용자가 홈 버튼을 눌렀는지 알 수 있습니다.

public static boolean isApplicationBroughtToBackground(final Activity activity) {
  ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);

  // Check the top Activity against the list of Activities contained in the Application's package.
  if (!tasks.isEmpty()) {
    ComponentName topActivity = tasks.get(0).topActivity;
    try {
      PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
      for (ActivityInfo activityInfo : pi.activities) {
        if(topActivity.getClassName().equals(activityInfo.name)) {
          return false;
        }
      }
    } catch( PackageManager.NameNotFoundException e) {
      return false; // Never happens.
    }
  }
  return true;
}

응용 프로그램 클래스에서 이 메서드를 간단히 호출할 수 있습니다.

ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                Log.e(TAG, "onStateChanged: " + event.toString());
            }
        });

Lifecycle.Event합니다.

ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
ON_ANY

앱이 백그라운드로 이동할 때 ON_PAUSE & ON_STOP을 반환하고 앱이 포그라운드로 이동할 때 ON_START & ON_RESUME을 반환합니다.

구글 애널리틱스 EasyTracker에서 사용하던 중에 작동했습니다.단순한 정수를 사용하여 원하는 작업을 수행하도록 확장할 수 있습니다.

public class MainApplication extends Application {

    int isAppBackgrounded = 0;

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

    private void appBackgroundedDetector() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle bundle) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStart(activity);
            }

            @Override
            public void onActivityResumed(Activity activity) {
                isAppBackgrounded++;
                if (isAppBackgrounded > 0) {
                    // Do something here
                }
            }

            @Override
            public void onActivityPaused(Activity activity) {
                isAppBackgrounded--;
            }

            @Override
            public void onActivityStopped(Activity activity) {
                EasyTracker.getInstance(MainApplication.this).activityStop(activity);
            }

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

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }
}

타임스탬프를 확인하지 않고 회전을 처리하는 접근법을 찾지 못했기 때문에, 저는 현재 우리가 어떻게 하는지도 앱에 공유한다고 생각했습니다. 답변 https://stackoverflow.com/a/42679191/5119746 에 유일하게 추가된 것은 오리엔테이션도 고려한다는 것입니다.

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {

   // Members

   private var mAppIsInBackground = false
   private var mCurrentOrientation: Int? = null
   private var mOrientationWasChanged = false
   private var mResumed = 0
   private var mPaused = 0

그런 다음 콜백을 위해 먼저 이력서를 작성합니다.

   // ActivityLifecycleCallbacks

   override fun onActivityResumed(activity: Activity?) {

      mResumed++

      if (mAppIsInBackground) {

         // !!! App came from background !!! Insert code

         mAppIsInBackground = false
      }
      mOrientationWasChanged = false
    }

활동 중지 시:

   override fun onActivityStopped(activity: Activity?) {

       if (mResumed == mPaused && !mOrientationWasChanged) {

       // !!! App moved to background !!! Insert code

        mAppIsInBackground = true
    }

그리고 다음과 같은 추가 사항이 있습니다.방향 변경 확인 중:

   override fun onConfigurationChanged(newConfig: Configuration) {

       if (newConfig.orientation != mCurrentOrientation) {
           mCurrentOrientation = newConfig.orientation
           mOrientationWasChanged = true
       }
       super.onConfigurationChanged(newConfig)
   }

바로 그겁니다.이것이 누군가에게 도움이 되기를 바랍니다 :)

정답은 여기에 있습니다.

아래와 같은 MyApp 이름의 클래스를 만듭니다.

public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {

    private Context context;
    public void setContext(Context context)
    {
        this.context = context;
    }

    private boolean isInBackground = false;

    @Override
    public void onTrimMemory(final int level) {
        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {


            isInBackground = true;
            Log.d("status = ","we are out");
        }
    }


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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

        if(isInBackground){

            isInBackground = false;
            Log.d("status = ","we are in");
        }

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }

    @Override
    public void onConfigurationChanged(Configuration configuration) {

    }

    @Override
    public void onLowMemory() {

    }
}

그런 다음 원하는 모든 곳(앱에서 더 나은 첫 번째 활동 시작)에 아래 코드를 추가합니다.

MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);

때 완!이제앱료에있을때표로다시니됩가그드운라그백이▁log▁done▁get다▁is표▁we니시됩▁now▁app완!▁the▁when료.status : we are out앱에 log ▁log다나▁and,▁get▁we니옵▁when로▁app그▁go.status : we are out

디바운스 논리를 사용하여 연속적인 백그라운드/포그라운드 이벤트를 발생시키지 않도록 하는 솔루션이 있습니다.따라서 항상 안정적인 배경/전경 상태를 반영합니다.

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import java.util.Timer
import java.util.TimerTask

/**
 * An observer class to listen on the app's lifecycle.
 */
class AppLifecycleObserver(
    private val onAppGoesToBackground: () -> Unit = {},
    private val onAppEntersForeground: () -> Unit = {}
) : LifecycleEventObserver {

    private val debounce = DebouncingTimer(timeout = 10)

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        debounce.refresh {
            when (event.targetState) {
                Lifecycle.State.CREATED -> onAppGoesToBackground()
                Lifecycle.State.RESUMED -> onAppEntersForeground()
                else -> Unit
            }
        }
    }

    fun attach() {
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
    }

    fun detach() {
        ProcessLifecycleOwner.get().lifecycle.removeObserver(this)
    }

    private class DebouncingTimer(private val timeout: Long) {

        private var timer: Timer? = null

        fun refresh(job: () -> Unit) {
            timer?.cancel()
            timer = Timer()
            timer?.schedule(object : TimerTask() {
                override fun run() = job.invoke()
            }, timeout)
        }
    }
}

다의인스생됩니다의 .AppLifecycleObserver:

private val appLifecycleObserver = AppLifecycleObserver(
        onAppGoesToBackground = { // do whatever... },
        onAppEntersForeground = { // do whatever... }
    )
// Attach the observer when it is needed:
appLifecycleObserver.attach()

// Remove when there is no need to it:
appLifecycleObserver.detach()

종속성의 적절한 버전을 추가하는 것을 잊지 마십시오.

implementation("androidx.lifecycle:lifecycle-process:$lifecycle_version")

제가 한 것은 모든 앱 내 활동이 다음과 같이 시작되도록 하는 것입니다.startActivityForResult그런 다음 onActivityResult가 Resume 이전에 호출되었는지 확인합니다.그렇지 않다면 앱 외부에서 방금 돌아왔다는 뜻입니다.

boolean onActivityResultCalledBeforeOnResume;

@Override
public void startActivity(Intent intent) {
    startActivityForResult(intent, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    onActivityResultCalledBeforeOnResume = true;
}

@Override
protected void onResume() {
    super.onResume();
    if (!onActivityResultCalledBeforeOnResume) {
        // here, app was brought to foreground
    }
    onActivityResultCalledBeforeOnResume = false;
}

은 @에서 영감을 받았고 창에 하지만, @d60402답에서영감받았을을 하지 않습니다.Timer:

public abstract class BaseActivity extends ActionBarActivity {

  protected boolean wasInBackground = false;

  @Override
  protected void onStart() {
    super.onStart();
    wasInBackground = getApp().isInBackground;
    getApp().isInBackground = false;
    getApp().lastForegroundTransition = System.currentTimeMillis();
  }

  @Override
  protected void onStop() {
    super.onStop();
    if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
      getApp().isInBackground = true;
  }

  protected SingletonApplication getApp(){
    return (SingletonApplication)getApplication();
  }
}

SingletonApplication는 의확니다입의 입니다.Application 명령어:

public class SingletonApplication extends Application {
  public boolean isInBackground = false;
  public long lastForegroundTransition = 0;
}

저는 조금 늦었다는 것을 알지만, 제가 아래와 같이 한 동안 이 모든 대답에 문제가 있다고 생각합니다. 그리고 그것은 완벽하게 작동합니다.

다음과 같은 활동 수명 주기 콜백을 만듭니다.

 class ActivityLifeCycle implements ActivityLifecycleCallbacks{

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

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    Activity lastActivity;
    @Override
    public void onActivityResumed(Activity activity) {
        //if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when  app has been killed or started for the first time
        if (activity != null && activity == lastActivity) 
        {
            Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
        }

        lastActivity = activity;
    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

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

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }
}

아래와 같이 애플리케이션 클래스에 등록하면 됩니다.

public class MyApp extends Application {

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

은 (글을 시점에서)한 안드로이드가 때문에 중 .applicationDidEnterBackground()또는applicationWillEnterForeground()콜백저는 @jenzz가 만든 AppState Library를 사용했습니다.

[AppState]는 앱 상태 변화를 모니터링하는 RxJava 기반의 단순하고 사후 대응적인 Android 라이브러리입니다.앱이 백그라운드로 이동하고 다시 포그라운드로 돌아올 때마다 가입자에게 알립니다.

알고 보니 이것이 바로 제가 필요로 했던 것이었습니다. 특히 제 앱에는 여러 가지 활동이 있어서 단순히 확인하는 것뿐이었습니다.onStart()또는onStop()활동을 중단하지 않을 것입니다.

먼저 다음과 같은 종속성을 Gradle에 추가했습니다.

dependencies {
    compile 'com.jenzz.appstate:appstate:3.0.1'
    compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}

그런 다음 코드의 적절한 위치에 다음 행을 추가하는 것이 간단한 문제였습니다.

//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
    @Override
    public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
        switch (appState) {
            case FOREGROUND:
                Log.i("info","App entered foreground");
                break;
            case BACKGROUND:
                Log.i("info","App entered background");
                break;
        }
    }
});

관찰 대상에 가입하는 방법에 따라 메모리 누수를 방지하기 위해 구독을 취소해야 할 수도 있습니다.github 페이지에 있는 더 많은 정보.

@d60402의 답변 수정본입니다. https://stackoverflow.com/a/15573121/4747587

거기서 언급된 모든 것을 하라.하지만 그것을 갖는 대신에.Base Activity을 모든 를 정하는 것.onResume()그리고.onPause다음을 수행합니다.

응용 프로그램 클래스에서 다음 행을 추가합니다.

registerActivityLifecycle콜백(응용프로그램)을 실행합니다.활동 라이프사이클콜백);

것이.callback에는 모든 주기 모든활수동주방가지있고법으며이제재수있할정다습니의을기명▁and있다▁now니습수▁you▁override▁has▁can▁methods▁all모▁lifecycle▁the든을 재정의할 수 있습니다.onActivityResumed()그리고.onActivityPaused().

Gist: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b 를 보십시오.

언급URL : https://stackoverflow.com/questions/4414171/how-to-detect-when-an-android-app-goes-to-the-background-and-come-back-to-the-fo

반응형