Android 응용프로그램이 백그라운드에서 실행 중인지 확인
배경에 관해서는, 현재 사용자가 볼 수 있는 애플리케이션 활동이 하나도 없다는 뜻입니다.
백그라운드에서 응용 프로그램이 실행 중인지 여부를 감지하는 방법은 몇 가지 있지만, 그 중 한 가지 방법만 완벽하게 신뢰할 수 있습니다.
올바른 솔루션(Dan, CommonsWare 및 NeTeInStEiN에게 제공)
다를 을 직접 합니다.Activity.onPause
,Activity.onResume
방법들. 다른에 "를 저장합니다일부 다른 클래스에 "가시성" 상태를 저장합니다.하는 것입니다.Application
아니면.Service
(서비스에서 활동 가시성을 확인하려면 이 솔루션에도 몇 가지 변형이 있습니다.)
tApplication
) 주:isActivityVisible()
정적 방법):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" >
더하다
onPause
그리고.onResume
모든 사람들에게Activity
에 대한 공통 상위 할 수 우)MapActivity
/ListActivity
으로 다음 등.함):@Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); }
액티비티 라이프사이클 콜백은 API 레벨 14(Android 4.0)에 추가되었습니다.응용프로그램의 활동이 현재 사용자에게 표시되는지 여부를 추적하는 데 사용할 수 있습니다.자세한 내용은 아래 콘스탁의 답변을 확인해보세요.
저는 다음과 같은 해결책을 제시하곤 했습니다.다음 목록을 반환하는 현재 전경/배경 응용 프로그램을 탐지할 수 있습니다.
RunningAppProcessInfo
기록. 하려면 checkRunningAppProcessInfo.importance
에 대한RunningAppProcessInfo.IMPORTANCE_FOREGROUND
하는 동안에RunningAppProcessInfo.processName
응용 프로그램 패키지 이름과 같습니다.를 하면.
ActivityManager.getRunningAppProcesses()
램 UI합니다를(를) 합니다.IMPORTANCE_FOREGROUND
당신의 업무를 위해 그것이 실제로 전경에 있든 없든.:다예:로)).AsyncTask
및 ) 합니다합니다.이 해결책이 효과적일 수도 있지만(그리고 실제로 대부분의 경우) 사용을 자제할 것을 강력히 권고합니다.그리고 그 이유는 이겁니다.Dianne Hackborn은 다음과 같이 썼습니다.
이러한 API는 응용 프로그램이 UI 흐름을 기반으로 하는 것이 아니라 실행 중인 응용 프로그램을 사용자에게 보여주거나 작업 관리자와 같은 작업을 수행하기 위한 것입니다.
네, 이 물건들에 대해 기억에 남는 목록이 있습니다.그러나 사용자와 별도로 실행되는 스레드에 의해 관리되는 다른 프로세스에서는 사용할 수 없으며, (a) 올바른 결정을 내릴 수 있는 시간을 확인하거나 (b) 돌아올 때까지 일관된 그림을 얻을 수 있을 것으로 기대할 수 없습니다.또한 "다음" 활동이 무엇인지에 대한 결정은 항상 스위치를 실행할 시점에서 이루어지며, 정확한 시점(스위치를 실행하기 위해 잠시 활동 상태가 잠기는 시점)이 되어서야 다음 활동이 무엇인지 확실히 알 수 있습니다.
그리고 이곳에서의 구현과 글로벌 행동이 미래에도 그대로 유지될 것을 보장받지는 못합니다.
SO에 답변을 올리기 전에 이 글을 읽었으면 좋았을 텐데, 제 잘못을 인정하기에 너무 늦지 않았으면 좋겠습니다.
또
Droid-Fu 라이브러리는 답변 용도 중 하나에 언급되어 있습니다.ActivityManager.getRunningTasks
s을 위하여isApplicationBroughtToBackground
방법. 를 보시고 그 사용하지 위의 Dianne의 코멘트를 보시고 그 방법도 사용하지 마세요.
구글 솔루션 - 이전 솔루션처럼 해킹이 아닙니다.프로세스 수명주기 소유자 사용
:
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
}
}
Java:
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
}
}
쾌활하게
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
이 답변 사용 안 함
사용자 1269737의 답변은 이를 위한 올바른 방법(Google/Android 승인)입니다.가서 그들의 대답을 읽고 +1을 주세요.
후세를 위해서 여기에 제 원답을 남겨두겠습니다.이것은 지난 2012년에는 가장 좋은 것이었지만, 지금은 안드로이드가 이에 대한 적절한 지원을 하고 있습니다.
원답
키는 사용하고 있습니다.ActivityLifecycleCallbacks
(이를 위해서는 Android API 레벨 14(Android 4.0)가 필요합니다.)중지된 활동의 수가 시작된 활동의 수와 동일한지 확인하기만 하면 됩니다.동일한 경우 응용프로그램이 백그라운드로 설정됩니다.시작된 활동이 더 많은 경우에도 응용프로그램이 계속 표시됩니다.일시 중지된 활동보다 재개된 활동이 더 많을 경우, 응용프로그램은 표시될 뿐만 아니라 전경에도 표시됩니다.활동이 보이는 상태와 보이는 상태, 보이는 상태와 보이는 상태, 보이는 상태는 아니지만 보이는 상태, 보이는 상태와 보이는 상태가 아닌 상태(즉, 배경)가 있습니다.
은 입니다 입니다.getRunningTasks()
다를 Activity
정/서에서 하기 위한 응용 .onResumed()
/onPaused()
몇 자체적으로 포함된 몇 줄의 코드일 뿐이며 애플리케이션 전체에서 작동합니다.게다가 필요한 펑키 권한도 없습니다.
내 라이프사이클 핸들러.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;
}
*/
}
내 응용 프로그램.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 활동을 볼 수 있지만 전경에는 보이지 않을 수 있습니다(예: 투명한 알림 오버레이가 있는 경우).그래서 제가 이 답변을 반영해서 업데이트한 것입니다.
아무것도 전경에 나타나지 않는 활동을 전환할 때 Android는 이상한 림보 모멘트를 가지고 있다는 것을 알아야 합니다.이러한 이유로 (동일한 앱에서) 활동 간 전환 시 응용 프로그램이 포그라운드에 있는지 확인하면 (앱이 여전히 활성화된 앱이고 눈에 띄어도) 포그라운드에 없다는 메시지가 표시됩니다.
에서 할 수 .Activity
의onPause()
메소드 후 super.onPause()
내가 말한 내가 방금 말한 이상한 림보 상태를 기억하세요.
, ) 에서 가 아닌 할 수 .Activity
의onStop()
메소드 후 super.onStop()
.
지원 라이브러리 버전 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);
안드로이드 API 16이기 때문에 앱이 포그라운드에 있는지 간단하게 확인할 수 있는 방법이 있습니다.그것은 완벽하지 않을 수도 있지만, 안드로이드의 어떤 방법도 완벽하지 않습니다.이 방법은 서비스가 서버로부터 업데이트를 수신하고 알림 표시 여부를 결정해야 할 때 사용하기에 충분합니다(UI가 포그라운드인 경우 사용자는 알림 없이 업데이트를 알 수 있기 때문입니다).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
아이돌론의 답변은 오류가 발생하기 쉽고 훨씬 복잡하지만 여기서 반복 확인 안드로이드 어플리케이션이 포그라운드인지 아닌지를 확인하고 여기서 백그라운드 작업 또는 서비스에서 현재 포그라운드 어플리케이션을 결정하는 것입니다.
훨씬 더 간단한 접근 방식이 있습니다.
모든 활동을 확장하는 기본 활동에 대해:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
응용프로그램 활동이 포그라운드에 있는지 확인해야 할 때마다 확인하십시오. isVisible()
;
이 접근 방식을 이해하려면 활동 수명 주기에 대한 다음 답변을 확인합니다.활동 라이프사이클 병행
저는 Application을 사용하는 추천 솔루션을 사용해 보았습니다.활동 라이프사이클 콜백 및 다른 많은 사람들이 이를 호출했지만 기대했던 대로 작동하지 않았습니다.Sarge 덕분에 아래에서 설명하는 꽤 쉽고 간단한 해결책을 생각해 냈습니다.
B를 A B A B 로 () 입니다이라고 부르지 를입니다.
ActivityA.finish
그런 활동 ), B.onStart()
활동 A 이전에 호출됩니다.onStop()
.
그것이 또한 사이의 주요한 차이점입니다.onStop()
그리고.onPause()
내가 읽은 기사에는 아무도 언급하지 않았다고 합니다.
이 를(를) 몇 번 셀 수 .onStart()
그리고.onPause()
당신의 프로그램에 불려갔습니다.각 항목에 대해 주의하십시오. Activity
당신의 프로그램의, 당신은 당신의 프로그램을 재정의해야 합니다.onStart()
그리고.onStop()
에 사용되는 하기 위해 됩니다.아래는 이 논리를 구현한 코드입니다.내가 확장된 클래스를 사용하고 있다는 것을 유의합니다.Application
잊지말고 .Manifest.xml
그: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--;
}
}
각에서 를 onStart()
그리고.onStop()
그리고 다음과 같이 증분/decre을 조정합니다.
@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();
}
이 논리를 사용하면 다음과 같은 두 가지 경우가 발생할 수 있습니다.
stateCounter = 0
되고 있음을 중지된 횟수는 시작된 활동의 횟수와 같으며, 이는 응용 프로그램이 백그라운드에서 실행되고 있음을 의미합니다.stateCounter > 0
. 즉,을 의미합니다 시작된 수가 중지된 수보다 더 크므로 응용프로그램이 전면에서 실행되고 있음을 의미합니다.
:stateCounter < 0
시작된 활동보다 중지된 활동이 더 많다는 것을 의미하며, 이는 불가능합니다.이 경우가 발생하면 카운터를 필요한 만큼 늘리거나 줄이는 것이 아님을 의미합니다.
당신은 갈 준비가 되었습니다.다 해야 합니다.onStop()
.
직접 추적하는 것 외에 활동이 가시적인지 아닌지를 판단할 방법은 없습니다.다른 구현 아이디어를 제공할 수 있도록 새로운 스택 오버플로우 질문을 해보고, 사용자 환경에서 달성하고자 하는 것이 무엇인지 설명하는 것을 고려해 보는 것이 좋습니다.
ComponentCallbacks2를 사용하여 앱이 백그라운드에 있는지 탐지할 수 있습니다.그건 그렇고 이 콜백은 API Level 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
}
}
}
@Cornstalks를 기반으로 구축하면 몇 가지 유용한 기능을 포함할 수 있습니다.
추가 기능:
- 단일 톤 패턴을 도입하여 애플리케이션의 어디에서나 이 작업을 수행할 수 있습니다. AppLifecycleHandler.isApplicationVisible() 및 AppLifecycleHandler.isApplicationInForeground()
- 중복 이벤트 처리 추가(댓글 // 가시성 변경에 대해 일부 조치를 취하고 // 전경 변경에 대해 일부 조치를 취함)
앱.자바
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;
}
}
제가 생각해낸 최고의 솔루션은 타이머를 사용합니다.
onPause()에서 타이머를 시작하고 onResume()에서 동일한 타이머를 취소한 경우 타이머 인스턴스가 1개(일반적으로 Application 클래스에 정의됨) 있습니다.타이머 자체가 2초 후(또는 적절하다고 생각하는 간격)에 실행 가능하도록 설정되어 있는데, 타이머가 실행되면 백그라운드에 있는 것으로 애플리케이션을 표시하는 플래그를 설정합니다.
타이머를 취소하기 전에 onResume() 메서드에서 백그라운드 플래그를 쿼리하여 시작 작업(예: 다운로드 시작 또는 위치 서비스 활성화)을 수행할 수 있습니다.
이 솔루션을 사용하면 백스택에서 여러 가지 작업을 수행할 수 있으며, 구현에 사용 권한이 필요하지 않습니다.
이 솔루션은 이벤트 버스를 사용하는 경우에도 잘 작동합니다. 타이머가 이벤트를 간단히 실행할 수 있고 앱의 다양한 부분이 그에 따라 반응할 수 있기 때문입니다.
개발자 설정 "활동을 유지하지 않음"을 설정할 경우, 작성된 활동의 수만 확인하면 부족합니다.SaveInstanceState(인스턴스 저장 상태)도 확인해야 합니다.사용자 지정 방법은 ApplicationRunning()입니다. 검사는 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) { }
}
CommonsWare와 Key가 말한 내용을 다시 생각해 보려면 Application 클래스를 확장하여 모든 활동에서 일시 중지/재개 방법으로 호출할 수 있습니다.이렇게 하면 어떤 활동이 표시되는지 알 수 있지만 이 작업을 더 잘 처리할 수 있습니다.
당신이 생각하고 있는 것을 정확하게 설명해 줄 수 있습니까?백그라운드에서 실행된다는 것은 애플리케이션이 현재 화면에 표시되지 않는데도 단순히 메모리에 남아 있는 것을 의미합니까?앱이 초점에 맞지 않을 때 서비스를 보다 지속적으로 관리할 수 있는 방법으로 사용해 본 적이 있습니까?
저는 Activity Lifecycle Callback을 직접 구현했습니다.셜록 액티비티를 사용하고 있지만 정상적인 액티비티 수업은 효과가 있을지도 모릅니다.
먼저 활동 라이프사이클을 추적할 수 있는 모든 방법을 갖춘 인터페이스를 만듭니다.
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());
}
}
세 번째로 셜록 액티비티에서 확장된 클래스를 만들고 있습니다.
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);
}
}
넷째, Sherlock Activity에서 확장된 모든 클래스를 My Sherlock Activity로 대체했습니다.
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
이제 로그캣에서 My Application에서 만들어진 인터페이스 구현에 프로그래밍된 로그를 볼 수 있습니다.
시스템은 포그라운드 앱과 백그라운드 앱을 구분합니다. (서비스 제한을 위한 백그라운드 정의는 메모리 관리에서 사용되는 정의와 다릅니다. 앱은 메모리 관리와 관련하여 백그라운드에 있을 수 있지만 서비스 시작 기능과 관련하여 포그라운드에 있을 수 있습니다.)다음 중 하나가 참일 경우 앱은 포그라운드로 간주됩니다.
- 활동이 시작되었든 일시 중지되었든 간에 눈에 보이는 활동이 있습니다.
- 포그라운드 서비스가 있습니다.
- 다른 포그라운드 앱은 서비스 중 하나에 바인딩되거나 콘텐츠 공급자 중 하나를 사용하여 앱에 연결됩니다.예를 들어, 다른 앱이 다음과 같이 바인딩되는 경우 앱이 포그라운드로 표시됩니다.
- IME
- 벽지서비스
- 알림 청취자
- 음성 또는 문자 서비스
이러한 조건이 모두 사실이 아니면 앱이 백그라운드에 있는 것으로 간주됩니다.
유일하게 정확한 해결책은 다음과 같습니다.
주 활동.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) {
...
}
}
}
어떤 해결책도 저에게 통하지 않지만, 저는 원안적인 해결책을 제안합니다.이 정도면 될 겁니다.isAppBackground return false이면 앱이 포그라운드에 있어야 합니다.
public static boolean isAppBackground(Context context){
boolean isBackground=true;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH){
List<ActivityManager.RunningAppProcessInfo> runningProcesses =activityManager.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo processInfo:runningProcesses){
if(processInfo.importance==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND){
for(String activeProcess:processInfo.pkgList){
if(activeProcess.equals(context.getPackageName())){
isBackground = false;
}
}
}
}
}else{
List<ActivityManager.RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);
if(taskInfo.size()>0) {
ComponentName componentName = taskInfo.get(0).topActivity;
if(componentName.getPackageName().equals(context.getPackageName())){
isBackground = false;
}
}
}
return isBackground;
}
대화상자 위에 있으면 활동이 일시 중지되므로 권장되는 모든 솔루션은 절반 솔루션입니다.대화 상자에 대한 후크도 만들어야 합니다.
나는 이 페이지를 통해 읽을 것을 추천합니다: http://developer.android.com/reference/android/app/Activity.html
말해, , 이 더 .onStop()
호출되었습니다.
아직 언급되지 않았으므로 독자들에게 Android Architecture 구성 요소를 통해 사용 가능한 ProcessLifecycleOwner를 살펴보라고 제안하겠습니다.
는 를(를) 합니다.foreground
그리고.background
어떤 조건에서도:
Java 코드:
private static boolean isApplicationForeground(Context context) {
KeyguardManager keyguardManager =
(KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardLocked()) {
return false;
}
int myPid = Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list;
if ((list = activityManager.getRunningAppProcesses()) != null) {
for (ActivityManager.RunningAppProcessInfo aList : list) {
ActivityManager.RunningAppProcessInfo info;
if ((info = aList).pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
}
return false;
}
코틀린 코드:
private fun isApplicationForeground(context: Context): Boolean {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardLocked) {
return false
}
val myPid = Process.myPid()
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
var list: List<ActivityManager.RunningAppProcessInfo>
if (activityManager.runningAppProcesses.also { list = it } != null) {
for (aList in list) {
var info: ActivityManager.RunningAppProcessInfo
if (aList.also { info = it }.pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
}
}
return false
}
간단하고 간단한 답변:
override fun onPause() {
Log.i("APP LIFECYCLE", "App Enter BACKground")
isForeground = false
super.onPause()
}
override fun onResume() {
Log.i("APP LIFECYCLE", "App Enter FOREground")
isForeground = true
super.onResume()
}
으로.isForeground
상태를 확인하기 위한 활동의 속성.
이 오래된 게시물에 대한 또 다른 해결책(도움이 될 수 있는 것에 대한):
<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();
}
}
on ActivityDestroyed 함수의 주석을 참조합니다.
SDK target version 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++;
}
}
공유 기본 설정을 사용하여 해당 속성을 저장하고 활동의 서비스 바인딩을 사용하여 해당 속성에 대해 작업을 수행해야 합니다.바인딩만 사용하는 경우(즉, startService를 사용하지 않는 경우) 서비스는 바인딩할 때만 실행되며(Resume에서 바인딩 및 일시 중지에서 바인딩 해제) 포그라운드에서만 실행되며 백그라운드에서 작업하려는 경우 일반 시작 중지 서비스를 사용할 수 있습니다.
저는 이 질문이 좀 더 명확해야 한다고 생각합니다.언제? 어디서?앱이 백그라운드에 있는지 알고 싶은 구체적인 상황은 무엇입니까?
저는 제 방식대로 제 해결책을 소개할 뿐입니다.
은 도"됩니다의 " 를 사용하여 이 합니다.RunningAppProcessInfo
onStop
다만 할 수 내.BaseActivity
.onStop
"중요도" 값을 확인하는 방법.코드는 다음과 같습니다.
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;
}
getApplicationState().isInForeground()를 사용하는 것은 어떻습니까?
제 생각에 많은 답변들이 많은 양의 코드를 도입하고 많은 복잡성과 가독성을 가져다 줍니다.
때 에 SO간의 의사소통 방법Service
그리고.Activity
, 저는 주로 지역 방송 관리자를 이용하라고 조언합니다.
왜요?
문서를 인용하면 다음과 같습니다.
당신이 방송하는 데이터는 당신의 앱을 떠나지 않을 것이므로, 개인 데이터 유출을 걱정할 필요는 없습니다.
다른 응용 프로그램에서 이러한 브로드캐스트를 사용자의 앱으로 전송하는 것은 불가능하므로 악용할 수 있는 보안 구멍에 대해 걱정할 필요가 없습니다.
시스템을 통해 글로벌 방송을 보내는 것보다 더 효율적입니다.
문서에 없음:
- 외부 라이브러리를 필요로 하지 않습니다.
- 코드가 최소입니다.
- 구현 및 이해가 빠릅니다.
- 맞춤형 자체 구현 콜백 / 울트라 싱글톤 / 프로세스 내 패턴이 전혀 없음...
- 에 대한 강력한 참조 없음
Activity
,Application
, ...
묘사
에 어떤 Activity
현재 전경에 있습니다.다에서 하잖아요.Service
, 아니면 당신의Application
급
은, 이,Activity
물체가 신호의 송신자가 됩니다(I'll on / I'll off).당신의.Service
는 , 에, 됩니다.Receiver
.
당신의 두 순간이 있습니다.Activity
전경으로 이동하는지 배경으로 이동하는지 알려줍니다(네, 두 개만...).6)이 아닙니다.
때.Activity
.onResume()
다림)).onCreate()
).
때.Activity
면,onPause()
라고 합니다.
이 의 이Activity
다에게 .Service
그것의 상태를 설명합니다.
Activity
의 것 , ?'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
m에서Service
에.Activity
켜지면 반응하고 작동합니다.
이 Service
고,고가 .Activity
현을 합니다.BroadcastReceiver
.
그래서, 만들어 보세요.Receiver
n에Activity
합니다.onResume()
합니다.onPause()
. 다른 라이프 사이클 방법을 사용할 필요는 없습니다.
합니다를 합니다.Receiver
에서의 행동onReceive()
함, 함, (update ListView,함,함 등).
으로 으로.Activity
앞에 있을 때만 들을 것이고 뒤에 있거나 파괴될 때는 아무 일도 일어나지 않을 것입니다.
Activity
쪽이든Activity
on다한다면)을 ).Receiver
).
모든 것이 배경에 있다면 아무도 응답하지 않을 것이고 신호는 그냥 사라질 것입니다.
에서의 데이터 Service
경유로Intent
신호 ID를 지정하여 (위의 코드 참조).
- Multi-Window 지원 제외.까다로울 수 있습니다. (필요한 경우 테스트해 보십시오.)...
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
}
특정 활동이 포그라운드에 있는지, 애플리케이션에 직접 액세스할 수 없는 SDK인 경우 특정 사례에 적합한 답변은 없습니다.저는 방금 새로운 채팅 메시지에 대한 푸시 알림을 받은 후 백그라운드 스레드에 있었고 채팅 화면이 맨 앞에 없는 경우에만 시스템 알림을 표시하려고 합니다.
으로.ActivityLifecycleCallbacks
다 논리를 를 만들었습니다.MyActivity
포어그라운드에 있는지 여부입니다.
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
}
}
}
언급URL : https://stackoverflow.com/questions/3667022/checking-if-an-android-application-is-running-in-the-background
'programing' 카테고리의 다른 글
게시물에서 '업데이트'를 클릭하는 것이 프로그램적으로 게시물을 만드는 것과 어떻게 다릅니까? (0) | 2023.10.04 |
---|---|
Excel VBA: ActiveCell이 "*string*"을 좋아하면 Case 선택 (0) | 2023.10.04 |
XPath, XQuery 및 XPointer의 차이 (0) | 2023.09.24 |
동일한 신호에 대해 여러 개의 신호 처리기를 갖는 것이 유효합니까? (0) | 2023.09.24 |
Python 클래스에서 __init__를 사용하는 이유는 무엇입니까? (0) | 2023.09.24 |