일정 시간이 지나면 전경으로 돌아올 때 특정 작업을 수행하는 앱을 작성하려고합니다. 앱이 백그라운드로 전송되거나 포 그라운드로 가져 오는 시점을 감지하는 방법이 있습니까?
일정 시간이 지나면 전경으로 돌아올 때 특정 작업을 수행하는 앱을 작성하려고합니다. 앱이 백그라운드로 전송되거나 포 그라운드로 가져 오는 시점을 감지하는 방법이 있습니까?
답변:
onPause()
및 onResume()
응용 프로그램을 다시 배경과 전경하게 될 때 방법이라고합니다. 그러나 응용 프로그램이 처음 시작될 때와 종료되기 전에 호출됩니다. 활동 에서 더 많은 것을 읽을 수 있습니다 .
백그라운드 또는 포 그라운드에있는 동안 응용 프로그램 상태를 얻는 직접적인 방법은 없지만이 문제에 직면하여 onWindowFocusChanged
및onStop
.
자세한 내용은 여기를 확인하십시오. Android : Android 앱이 백그라운드로 이동하고 getRunningTasks 또는 getRunningAppProcesses없이 전경으로 돌아 오는시기를 감지하는 솔루션 입니다.
2018 년 3 월 업데이트 : 이제 더 나은 솔루션이 있습니다. ProcessLifecycleOwner를 참조하십시오 . 새로운 아키텍처 구성 요소 1.1.0 (현재는 최신 버전)을 사용해야하지만 특별히 위해 설계되었습니다.
이 답변 에는 간단한 샘플 이 있지만 샘플 앱 과 블로그 게시물을 작성했습니다. 을 작성했습니다.
2014 년에 이것을 쓴 이후로 다른 솔루션이 생겼습니다. 일부는 효과가 있었고 일부는 효과가 있다고 생각되었습니다 되었지만 (내를 포함하여!) 결함이 있었고 커뮤니티 (Android)로서 우리는 그 결과에 따라 생활하는 법을 배우고 특별한 경우에 대한 해결책을 썼습니다.
하나의 코드 스 니펫이 원하는 솔루션이라고 가정하지 마십시오. 더 나은 방법은 무엇을하고 왜 그렇게하는지 이해하는 것입니다.
이 MemoryBoss
클래스는 실제로 여기에서 작성된대로 사용되지 않았습니다. 작동하는 의사 코드 일뿐입니다.
새로운 아키텍처 구성 요소를 사용하지 않아야 할 정당한 이유가없는 한 (특히 오래된 오래된 API를 대상으로하는 경우 일부가있는 경우) 계속 사용하십시오. 그들은 완벽하지는 않지만 둘 다 아닙니다 ComponentCallbacks2
.
업데이트 / 참고 사항 (2015 년 11 월) : 사람들은 두 가지 의견을 제시했습니다. 먼저 문서 에서 정확한 값을 확인해서는 안되기 때문에 >=
대신 사용해야합니다 . 이것은 당신이 경우 것이 대부분의 경우 미세하지만 곰 염두에두고 있습니다 만 하고 신경 뭔가를 앱이 배경에 갔을 때, 사용 ==해야합니다 및 도 (활동 라이프 사이클 콜백과 같은) 다른 솔루션과 결합하거나, 원하는 효과를 얻지 못할 수 있습니다. 예 (그리고 이것은 나에게 일어났다)는 당신이 잠그고 싶다면==
백그라운드로 갈 때 암호 화면이있는 앱 (예 : 친숙한 경우 1Password와 같이), 메모리가 부족하고 갑자기 테스트하는 경우 실수로 앱을 잠글 수 있습니다 >= TRIM_MEMORY
.Android에서 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);
}
}
대화 상자가 활동을 일시 중지 할 수 있으므로 전체 화면 대화 상자가 표시 된 경우 응용 프로그램이 "배경으로 갔다"고 생각하지 않기를 원하지만 마일리지가 다를 수 있기 때문에 onStart를 권장합니다.
그리고 그게 전부입니다. 은 if 블록의 코드는 것이다 번만 실행되는 다른 활동으로 이동하더라도, 새 (또한 extends BaseActivity
보고는) wasInBackground
이며 false
,이 코드를 실행하지 않도록 할 때까지 onMemoryTrimmed
호출되고 플래그가 다시 true로 설정되어 .
희망이 도움이됩니다.
업데이트 / 참고 사항 (2015 년 4 월) :이 코드에 대한 모든 복사 및 붙여 넣기 전에 100 % 신뢰할 수 없으며 최상의 결과를 얻으려면 다른 방법과 결합 해야하는 몇 가지 인스턴스를 발견했습니다 . 특히, 거기에 이 개 알려진 경우onTrimMemory
콜 다시 실행되도록 보장되지는 :
앱이 표시되어있는 동안 휴대 전화가 화면을 잠그면 (예 : 기기가 nn 분 후에 잠김) 잠금 화면이 맨 위에 있기 때문에이 콜백은 호출되지 않습니다 (또는 항상 그런 것은 아닙니다).
장치의 메모리가 부족하고 메모리가 부족한 경우 운영 체제는이 호출을 무시하고보다 중요한 수준으로 바로 넘어갑니다.
이제 앱이 백그라운드로 이동 한 시점을 아는 것이 얼마나 중요한지에 따라 활동 수명주기 등을 추적하면서이 솔루션을 함께 확장해야 할 수도 있고 그렇지 않을 수도 있습니다.
위의 사항을 명심하고 좋은 품질 보증 팀을 확보하십시오.)
업데이트 종료
늦었을 수도 있지만 Ice Cream Sandwich (API 14) 및 Above에 신뢰할 수있는 방법이 있습니다.
앱에 더 이상 UI가 표시되지 않으면 콜백이 트리거됩니다. 사용자 정의 클래스에서 구현할 수있는 콜백을 ComponentCallbacks2 라고합니다 (예, 둘). 이 콜백은 API 레벨 14 (Ice Cream Sandwich) 이상 에서만 사용할 수 있습니다 .
기본적으로 메소드를 호출합니다.
public abstract void onTrimMemory (int level)
레벨은 구체적으로 20 이상입니다
public static final int TRIM_MEMORY_UI_HIDDEN
나는 이것을 테스트 해왔으며 항상 작동합니다. 레벨 20은 앱이 더 이상 표시되지 않기 때문에 일부 리소스를 해제하려는 "추천"일뿐입니다.
공식 문서를 인용하려면 :
onTrimMemory (int) 레벨 : 프로세스에 사용자 인터페이스가 표시되어 더 이상 그렇게하지 않습니다. 이 시점에서 메모리를보다 잘 관리 할 수 있도록 UI를 통한 많은 할당을 해제해야합니다.
물론, 실제로 말한 것을 수행하기 위해 이것을 구현해야합니다 (특정 시간 동안 사용되지 않은 메모리를 제거하고 사용하지 않은 일부 컬렉션을 지우십시오 등) 가능성은 무한합니다 (다른 가능한 자세한 내용은 공식 문서를 참조하십시오) 임계 수준).
그러나 흥미로운 점은 OS가 말하고 있다는 것입니다. HEY, 앱이 백그라운드로 갔다!
처음에 정확히 알고 싶었던 것입니다.
언제 돌아 왔는지 어떻게 알 수 있습니까?
쉽게 글쎄, 난 당신 때문에 당신이 "BaseActivity"가 확신 할 수 플래그 사실 당신있는 거 다시 당신의 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.
}
}
이것을 사용하려면 응용 프로그램 구현 ( RIGHT? )에서 다음과 같이하십시오.
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
API (14) 아래에 아무것도에 사용 (2없이) 콜백 만 가지고 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);
그리고 그게 다야.
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
업데이트 2, 포인트 2의 문제를 피하는 데 사용 합니다. 포인트 1과 관련하여 앱이 실제로 백그라운드로 이동하지 않았기 때문에 문제가되지 않습니다. 그래서 그것이 작동해야합니다.
이 문제를 해결하는 방법은 다음과 같습니다. 활동 전환 사이의 시간 참조를 사용하면 앱이 "배경"인지 여부에 대한 적절한 증거를 제공 할 가능성이 높습니다.
먼저, 타이머, TimerTask, 한 활동에서 다른 활동으로의 전환이 합리적으로 걸릴 수있는 최대 밀리 초 수를 나타내는 상수가있는 android.app.Application 인스턴스 (MyApplication이라고 함)를 사용했습니다. 값이 2s)이고 앱이 "백그라운드"인지 여부를 나타내는 부울 값입니다.
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 () 및 onPause () 이벤트에서 또는 바람직하게는 모든 구체적인 활동이 상속하는 기본 활동에서 이러한 각 메소드에 대한 호출을 추가하는 것입니다.
@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 ()가 타이머를 시작하지만 거의 즉시 입력되는 새 활동이 최대 전환 시간에 도달하기 전에 타이머를 취소합니다. 그래서 wasInBackground 는 거짓 일 것입니다 입니다.
반면에 런처에서 활동이 포 그라운드로 오면 디바이스 깨우기, 전화 끊기 등이이 이벤트 이전에 실행 된 타이머 작업보다 많았으므로 wasInBackground 가 true 로 설정되었습니다 .
편집 : 새로운 아키텍처 구성 요소는 유망한 것을 가져 왔습니다 : ProcessLifecycleOwner , @vokilam의 답변 참조
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
}
}
}
예. 우리는 여기에 너무 많은 이상한 해결책이 있기 때문에이 간단한 해결책이 효과가 있다고 믿기가 어렵다는 것을 알고 있습니다.
그러나 희망이 있습니다.
ProcessLifecycleOwner
유망한 솔루션 인 것 같습니다.
ProcessLifecycleOwner는 첫 번째 활동이 이러한 이벤트를 진행함에 따라
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"
implementation "android.arch.lifecycle:extensions:1.0.0"
하고 annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
(즉, 구글의 저장소에서 google()
)
Martín 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;
}
}
}
그런 다음 이것을 Application 클래스의 onCreate ()에 추가하십시오.
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
이 방법을 사용합니다. 작동하기에는 너무 단순 해 보이지만 앱에서 잘 테스트되었으며 실제로 "홈"버튼, "리턴"버튼 또는 화면 잠금 후 홈 화면으로 이동하는 것을 포함하여 모든 경우에 놀랍도록 잘 작동합니다. 시도 해봐.
아이디어는 포 그라운드에서 Android가 항상 이전 활동을 중지하기 전에 항상 새로운 활동을 시작한다는 것입니다. 보장되지는 않지만 작동 방식입니다. 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 ()로 이동했습니다. 또한 초기 코드에서 누락 된 슈퍼 호출을 추가하고 있습니다. 이는 작동 코드보다 개념이기 때문입니다.
onStop is called when the activity is no longer visible to the user
.
앱이 여러 활동 및 / 또는 탭 막대 위젯과 같은 누적 활동으로 구성된 경우 onPause () 및 onResume ()을 재정의하면 작동하지 않습니다. 즉, 새로운 활동을 시작할 때 새로운 활동이 생성되기 전에 현재 활동이 일시 중지됩니다. 활동을 완료 할 때 ( "뒤로"단추 사용) 동일하게 적용됩니다.
원하는대로 작동하는 두 가지 방법을 찾았습니다.
첫 번째는 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 권한이 필요하지 않습니다. 대신 구현하기가 조금 더 복잡합니다.
MainApplication 클래스에는 응용 프로그램에서 실행중인 활동 수를 추적하는 변수가 있습니다. 각 활동에 대한 onResume ()에서 변수를 늘리고 onPause ()에서 변수를 줄입니다.
실행중인 활동 수가 0에 도달하면 다음 조건에 해당하는 경우 애플리케이션이 백그라운드에 놓입니다.
애플리케이션이 백그라운드로 사임되었음을 감지 할 수 있으면 애플리케이션이 다시 포 그라운드로 돌아올 때이를 쉽게 감지 할 수 있습니다.
확장 하는 클래스 를 만듭니다 Application
. 그런 다음 재정의 방법을 사용할 수 있습니다 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
}
}
FragmentActivity
당신은 또한 추가 할 수 있습니다 level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
너무.
onUserLeaveHint 사용을 고려하십시오. 앱이 백그라운드로 들어갈 때만 호출됩니다. onPause는 다른 이유로 호출 될 수 있으므로 처리해야 할 코너 케이스가 있습니다. 예를 들어, 사용자가 설정 페이지와 같은 앱에서 다른 활동을 열면 주 활동의 onPause 메소드가 여전히 앱에 있어도 호출됩니다. 무슨 일이 일어나고 있는지 추적하면 대신 요청하는 것을 수행하는 onUserLeaveHint 콜백을 간단히 사용할 수있을 때 버그가 발생합니다.
UserLeaveHint가 호출되면 부울 inBackground 플래그를 true로 설정할 수 있습니다. onResume이 호출되면 inBackground 플래그가 설정된 경우에만 전경으로 돌아 왔다고 가정하십시오. 사용자가 설정 메뉴에 있고 앱을 떠나지 않은 경우 기본 활동에서 onResume이 호출되기 때문입니다.
설정 화면에서 사용자가 홈 버튼을 누르면 설정 활동에서 onUserLeaveHint가 호출되고 설정 활동에서 onResume이 호출 될 때 기억됩니다. 기본 활동에이 탐지 코드 만있는 경우이 사용 사례를 놓치게됩니다. 코드를 복제하지 않고 모든 활동에이 코드를 사용하려면 활동을 확장하는 추상 활동 클래스를 작성하고 공통 코드를 입력하십시오. 그런 다음 각 활동이이 추상 활동을 확장 할 수 있습니다.
예를 들면 다음과 같습니다.
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 {
...
}
ActivityLifecycleCallbacks 는 관심이있을 수 있지만 잘 문서화되어 있지 않습니다.
registerActivityLifecycleCallbacks () 를 호출 하면 활동이 작성, 소멸되는 등의 콜백을 얻을 수 있어야합니다 . 활동에 대해 getComponentName ()을 호출 할 수 있습니다 .
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을 참조하십시오.
응용 프로그램에서 콜백을 추가하고 다음과 같은 방법으로 루트 활동을 확인하십시오.
@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();
}
}
});
}
Github app-foreground-background-listen 에서 프로젝트를 만들었습니다.
애플리케이션의 모든 활동에 대한 BaseActivity를 작성하십시오.
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
}
}
이제이 BaseActivity를 MainActivity와 같이 모든 Activity의 수퍼 클래스로 사용하십시오 .BaseActivity가 확장되고 응용 프로그램을 시작할 때 onAppStart가 호출되고 응용 프로그램이 어떤 화면에서 백그라운드로 갈 때 onAppPause ()가 호출됩니다.
ProcessLifecycleOwner를 사용하면 매우 쉽습니다.
이 의존성을 추가하십시오
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/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
라이프 사이클 관찰자를 첨부하는 ProcessLifecycleOwner 를 사용할 수 있습니다 .
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()
Application 클래스에서 다음을 호출합니다.
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
이를 통해 백그라운드에서 발생할 때 발생하는 응용 프로그램 ON_PAUSE
및 이벤트의 이벤트를 캡처 할 수 있습니다 ON_STOP
.
전체 애플리케이션이 백그라운드 / 전경이 될 때 알려주는 간단한 수명주기 방법은 없습니다.
나는 간단한 방법으로 이것을했다. 응용 프로그램 배경 / 전경 단계를 감지하려면 아래 지침을 따르십시오.
약간의 해결 방법으로 가능합니다. 여기서 ActivityLifecycleCallbacks 가 구출됩니다. 단계별로 살펴 보겠습니다.
먼저 android.app.Application 을 확장 하고 ActivityLifecycleCallbacks 인터페이스를 구현 하는 클래스를 만듭니다 . Application.onCreate ()에서 콜백을 등록하십시오.
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
아래와 같이 매니페스트에“앱”클래스를 등록하십시오 <application android:name=".App"
.
앱이 포 그라운드에있을 때 시작 상태에있는 활동이 하나 이상 있고 앱이 백그라운드에있을 때 시작 상태에있는 활동이 없습니다.
“App”클래스에서 아래와 같이 2 개의 변수를 선언하십시오.
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
시작된 상태 의 활동 수를 유지합니다 . isActivityChangingConfigurations
현재 활동이 방향 전환과 같은 구성 변경을 진행 중인지 여부를 나타내는 플래그입니다.
다음 코드를 사용하면 앱이 포 그라운드인지 감지 할 수 있습니다.
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
앱이 백그라운드인지 확인하는 방법입니다.
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
작동 방식 :
Lifecycle 메소드가 순차적으로 호출되는 방식으로 수행되는 약간의 트릭입니다. 시나리오를 살펴 보겠습니다.
사용자가 앱을 시작하고 실행기 활동 A가 시작되었다고 가정합니다. 수명주기 통화는
A.onCreate ()
A.onStart () (++ activityReferences == 1) (앱이 Foreground에 들어감)
A.onResume ()
이제 활동 A가 활동 B를 시작합니다.
A.onPause ()
B.onCreate ()
B.onStart () (++ activityReferences == 2)
B.onResume ()
A.onStop () (--activityReferences == 1)
그런 다음 사용자는 활동 B에서 다시 탐색합니다.
B.onPause ()
A.onStart () (++ activityReferences == 2)
A.onResume ()
B.onStop () (--activityReferences == 1)
B.onDestroy ()
그런 다음 사용자는 홈 버튼을 누릅니다.
A.onPause ()
A.onStop () (--activityReferences == 0) (앱이 백그라운드에 들어감)
사용자가 뒤로 버튼 대신 액티비티 B에서 홈 버튼을 누르면 여전히 동일하며 액티비티 참조는 0
. 따라서 백그라운드로 진입하는 앱으로 감지 할 수 있습니다.
그래서, 역할은 isActivityChangingConfigurations
무엇입니까? 위 시나리오에서 활동 B가 방향을 변경한다고 가정하십시오. 콜백 시퀀스는
B.onPause ()
B.onStop () (--activityReferences == 0) (앱이 백그라운드로 들어 갑니까 ??)
B.onDestroy ()
B.onCreate ()
B.onStart () (++ activityReferences == 1) (앱이 Foreground로 들어 갑니까 ??)
B.onResume ()
그렇기 때문에 isActivityChangingConfigurations
활동이 구성 변경을 겪을 때 시나리오를 피하기 위해 추가 검사가 필요한 이유 입니다.
전경 또는 배경을 입력하는지 여부에 관계없이 응용 프로그램을 감지하는 좋은 방법을 찾았습니다. 여기 내 코드가 있습니다. 이것이 당신을 돕기를 바랍니다.
/**
* 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 디버깅 및 개발 용으로 만 사용됩니다 것을 알 수있다. 타이머를 사용하고 거의 좋은 새로운 체계로 아래 GitHub 프로젝트를 업데이트 할 시간이 생기면이 게시물을 업데이트 할 것입니다.
편집 1 : 블로그 게시물 을 작성 하고 이를 쉽게하기 위해 간단한 GitHub 저장소 를 만들었습니다 .
인정 된 답변과 최고 등급의 답변이 모두 최선의 방법은 아닙니다. 최상위 응용 프로그램의 isApplicationBroughtToBackground () 구현은 응용 프로그램의 기본 활동이 동일한 응용 프로그램에 정의 된 활동으로 양보되는 상황을 처리하지 않지만 Java 패키지는 다릅니다. 나는이 경우에 효과가있는 방법을 생각해 냈습니다.
onPause ()에서 이것을 호출하면 다른 응용 프로그램이 시작되었거나 사용자가 홈 버튼을 눌렀 기 때문에 응용 프로그램이 백그라운드로 가고 있는지 알려줍니다.
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;
}
정답은 여기
아래와 같이 이름이 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);
끝난! 이제 앱이 백그라운드에 있으면 로그 status : we are out
가 표시되고 앱에 들어가면 로그가 표시됩니다.status : we are out
내 솔루션은 @ 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;
}
Google Analytics 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) {
}
});
}
}
나는 그것의 조금 늦게 알고 있지만 아래 에서처럼하고 모든 것이 완벽하게 작동하는 동안이 모든 대답에 몇 가지 문제가 있다고 생각합니다.
다음과 같이 액티비티 라이프 사이클 콜백을 만듭니다.
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());
}
이 나타납니다 안드로이드는 아이폰 OS의 등가물이없는 (이 글을 쓰는 현재)부터 안드로이드에서 가장 복잡한 문제 중 하나가 될 수 있습니다 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
의를 아래 수행
애플리케이션 클래스에서 다음 행을 추가하십시오.
registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks 콜백);
이 callback
모든 활동의 라이프 사이클 방식을 가지고 있으며, 당신은 지금 대체 할 수 있습니다 onActivityResumed()
와 onActivityPaused()
.
이 요지를 살펴보십시오 : https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
당신의 도움으로 쉽게 달성 할 수 ActivityLifecycleCallbacks
및ComponentCallbacks2
다음과 같은.
AppLifeCycleHandler
상기 인터페이스 위에 구현 하는 클래스를 작성하십시오 .
package com.sample.app;
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;
/**
* Created by Naveen on 17/04/18
*/
public class AppLifeCycleHandler
implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
AppLifeCycleCallback appLifeCycleCallback;
boolean appInForeground;
public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
this.appLifeCycleCallback = appLifeCycleCallback;
}
@Override
public void onActivityResumed(Activity activity) {
if (!appInForeground) {
appInForeground = true;
appLifeCycleCallback.onAppForeground();
}
}
@Override
public void onTrimMemory(int i) {
if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
appInForeground = false;
appLifeCycleCallback.onAppBackground();
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@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() {
}
interface AppLifeCycleCallback {
void onAppBackground();
void onAppForeground();
}
}
클래스에서 앱이 전경과 배경 사이를 전환 할 때 콜백을 얻도록 Application
구현 AppLifeCycleCallback
을 확장 합니다. 아래와 같은 것.
public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{
@Override
public void onCreate() {
super.onCreate();
AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
registerActivityLifecycleCallbacks(appLifeCycleHandler);
registerComponentCallbacks(appLifeCycleHandler);
}
@Override
public void onAppBackground() {
Log.d("LifecycleEvent", "onAppBackground");
}
@Override
public void onAppForeground() {
Log.d("LifecycleEvent", "onAppForeground");
}
}
도움이 되었기를 바랍니다.
편집 대안으로 이제 수명주기 인식 아키텍처 구성 요소를 사용할 수 있습니다.
타임 스탬프를 확인하지 않고 회전을 처리하는 접근법을 찾지 못했기 때문에 이제 앱에서 어떻게 수행하는지 공유한다고 생각했습니다. 이 답변 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
}
그리고 onActivityStopped :
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)
}
그게 다야. 희망이 누군가에게 도움이되기를 바랍니다 :)
다음을 사용 하여이 솔루션 을 확장 할 수 있습니다 LiveData
.
class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {
private var lifecycleListener: LifecycleObserver? = null
override fun onActive() {
super.onActive()
lifecycleListener = AppLifecycleListener().also {
ProcessLifecycleOwner.get().lifecycle.addObserver(it)
}
}
override fun onInactive() {
super.onInactive()
lifecycleListener?.let {
this.lifecycleListener = null
ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
}
}
internal inner class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
value = State.FOREGROUND
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
value = State.BACKGROUND
}
}
enum class State {
FOREGROUND, BACKGROUND
}
}
이제이 LiveData를 구독하고 필요한 이벤트를 잡을 수 있습니다. 예를 들면 다음과 같습니다.
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
이 답변은 정확하지 않은 것 같습니다. 이 메소드는 다른 활동이 시작되고 종료 될 때도 호출됩니다. 당신이 할 수있는 일은 글로벌 플래그를 유지하고 (예, 글로벌은 나쁘다 :) 새로운 활동을 시작할 때마다 이것을 true로 설정하십시오. 각 활동의 onCreate에서이를 false로 설정하십시오. 그런 다음 onPause에서이 플래그를 확인합니다. 거짓 인 경우 앱이 백그라운드로 이동하거나 종료됩니다.