배경에 따르면, 현재 응용 프로그램의 활동이 사용자에게 보이지 않는 것을 의미합니까?
배경에 따르면, 현재 응용 프로그램의 활동이 사용자에게 보이지 않는 것을 의미합니까?
답변:
애플리케이션이 백그라운드에서 실행 중인지 여부를 감지하는 몇 가지 방법이 있지만 그 중 하나만 완전히 신뢰할 수 있습니다.
올바른 솔루션 (신용은 Dan , CommonsWare 및 NeTeInStEiN으로 이동 ) , 메소드를
사용하여 애플리케이션의 가시성을 추적하십시오 . 다른 클래스에 "가시성"상태를 저장하십시오. 올바른 선택은 또는의 자체 구현입니다 ( 서비스에서 활동 가시성을 확인하려는 경우이 솔루션의 변형 도 있습니다 ). 예
사용자 정의 구현 클래스 (음 정적 방법) :Activity.onPause
Activity.onResume
Application
Service
Application
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();
}
ActivityLifecycleCallbacks 업데이트 는 API 레벨 14 (Android 4.0)에서 추가되었습니다. 이를 사용하여 애플리케이션 활동이 현재 사용자에게 표시되는지 여부를 추적 할 수 있습니다. 자세한 내용은 아래 Cornstalks의 답변을 확인하십시오.
내가 다음 해결책을 제안하는 데 잘못 사용한 것 :
레코드
ActivityManager.getRunningAppProcesses()
목록을 리턴하는 현재 포 그라운드 / 백그라운드 애플리케이션을 감지 할 수 있습니다RunningAppProcessInfo
. 응용 프로그램이 전경에 있는지 확인RunningAppProcessInfo.importance
하는RunningAppProcessInfo.IMPORTANCE_FOREGROUND
동안 whileRunningAppProcessInfo.processName
과 동일한 지 하십시오. 응용 프로그램 패키지 이름과 같습니다.또한
ActivityManager.getRunningAppProcesses()
응용 프로그램 UI 스레드에서 호출하면IMPORTANCE_FOREGROUND
실제로 포 그라운드에 있는지 여부에 관계없이 작업의 중요도 를 반환합니다 . 백그라운드 스레드에서 (예 :을 통해AsyncTask
) 호출하면 올바른 결과가 반환됩니다.
이 솔루션은 작동하지만 실제로는 대부분 작동하지만 사용하지 않는 것이 좋습니다. 그리고 여기에 이유가 있습니다. Dianne Hackborn은 다음과 같이 썼습니다 .
이러한 API는 애플리케이션이 UI 흐름을 기반으로하는 것이 아니라 사용자에게 실행중인 앱 또는 작업 관리자 등을 표시하는 것과 같은 작업을 수행하기위한 것입니다.
그렇습니다. 이러한 것들에 대한 목록이 메모리에 보관되어 있습니다. 그러나 다른 프로세스에서는 꺼져 있으며 사용자와 별도로 실행되는 스레드로 관리되며 (a) 올바른 결정을 내릴 시간을 보거나 (b) 돌아올 때까지 일관된 그림을 가질 수는 없습니다. 또한 "다음"활동에 대한 결정은 항상 스위치가 발생할 지점에서 수행되며, 정확한 시점 (활동 상태가 잠깐 동안 스위치를 수행하기 위해 잠긴 지점)까지는 아닙니다. 실제로 다음 일이 무엇인지 확실히 알고 있습니다.
그리고 여기에서의 구현과 글로벌 행동이 미래에도 동일하게 유지되는 것은 아닙니다.
나는 SO에 대한 답변을 게시하기 전에 이것을 읽었기를 바란다. 그러나 내 오류를 인정하기에는 너무 늦지 않았기를 바란다.
답변 중 하나에서 언급 된 또 다른 잘못된 솔루션
Droid-Fu 라이브러리는 ActivityManager.getRunningTasks
해당 isApplicationBroughtToBackground
방법에 사용 합니다 . 위의 Dianne의 의견을 참조하고 해당 방법을 사용하지 마십시오.
OnStop
요청합니다 isActivityVisible
.
user1269737의 답변은 올바른 (Google / Android 승인) 방법 입니다. 그들의 답변을 읽고 +1하십시오.
나는 후손을 위해 원래의 대답을 여기에 남겨 둘 것이다. 이것은 2012 년에 가장 잘 사용되었지만 이제는 Android가이를 올바르게 지원합니다.
열쇠는 사용 중입니다 ActivityLifecycleCallbacks
(Android API 레벨 14 (Android 4.0)가 필요합니다). 중지 된 활동 수가 시작된 활동 수와 같은지 확인하십시오. 동일하면 응용 프로그램의 배경 지식이있는 것입니다. 시작된 활동이 더 있으면 응용 프로그램이 여전히 표시됩니다. 일시 정지 된 활동보다 재개 된 경우 응용 프로그램이 표시 될뿐만 아니라 포 그라운드에도 있습니다. 활동은 다음과 같은 3 가지 주요 상태로 표시됩니다. 표시 및 포 그라운드, 표시되지만 포 그라운드에서는 표시되지 않고 포 그라운드에서는 표시되지 않습니다 (예 : 백그라운드).
이 방법에 대한 정말 좋은 점은 비동기 문제가되지 않는다는 것입니다 getRunningTasks()
않지만, 당신은 또한 모든를 수정할 필요가 없습니다 Activity
에서 설정 / 해제 뭔가를 응용 프로그램에서 onResumed()
/ onPaused()
. 자체 포함 된 몇 줄의 코드 일 뿐이며 전체 응용 프로그램에서 작동합니다. 또한 펑키 권한도 필요하지 않습니다.
MyLifecycleHandler.java :
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// I use four separate variables here. You can, of course, just use two and
// increment/decrement them instead of using four and incrementing them all.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
android.util.Log.w("test", "application is visible: " + (started > stopped));
}
// If you want a static function you can use to check if your application is
// foreground/background, you can use the following:
/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/
}
MyApplication.java :
// Don't forget to add it to your manifest by doing
// <application android:name="your.package.MyApplication" ...
public class MyApplication extends Application {
@Override
public void onCreate() {
// Simply add the handler, and that's it! No need to add any code
// to every activity. Everything is contained in MyLifecycleHandler
// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(new MyLifecycleHandler());
}
}
@Mewzer는이 답변에 대해이 답변에 대해 모든 사람들에게 응답하고 싶은 좋은 질문을했습니다.
onStop()
메모리 부족 상황에서는 호출되지 않습니다. 그게 문제입니까?
아니요. 문서는 다음과 같이 onStop()
말합니다.
onPause () 메소드를 호출 한 후 활동 프로세스를 계속 실행할 수있는 메모리가 부족한 메모리가 부족한 상황에서는이 메소드를 호출 할 수 없습니다.
여기서 핵심은 "활동의 프로세스를 계속 실행하는 것"입니다. 메모리가 부족한 상황에 도달하면 프로세스는 실제로 활동이 아니라 종료됩니다. 이는 a) 프로세스가 종료 된 경우 어쨌든 백그라운드를 확인할 수 없으며 b) 프로세스가 다시 시작되는 경우 (새로운 활동이 작성 되었기 때문에) 에 대한 변수 (정적이든 아니든) MyLifecycleHandler
는로 재설정됩니다 0
.
구성 변경에도 적용됩니까?
기본적으로 아니요. 매니페스트 파일에서 명시 적으로 설정하고 configChanges=orientation|screensize
( |
다른 것을 사용하여) 구성 변경을 처리해야합니다. 그렇지 않으면 활동이 삭제되고 다시 작성됩니다. 이를 설정하지 않으면 활동의 메소드가 다음 순서로 호출됩니다 onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. 보시다시피 겹침이 없습니다 (일반적으로 두 활동을 전환 할 때 두 활동이 아주 짧게 겹칩니다. 이는 백그라운드 감지 방법이 작동하는 방식입니다). 이 문제를 해결하려면 configChanges
활동이 파괴되지 않도록 설정해야합니다 . 다행히도 설정해야했습니다configChanges
전체 활동이 화면 회전 / 크기 조정에서 파괴되는 것이 바람직하지 않았기 때문에 이미 모든 프로젝트에 이미 있었기 때문에 문제가되지 않았습니다. (내 기억을 상쾌하게하고 나를 고쳐 주신 dpimka에 감사드립니다!)
참고 사항 :
이 답변에서 "배경"이라고 말하면 "앱이 더 이상 표시되지 않습니다."라는 의미입니다. 안 드 로이드 활동은 아직 보이지 않지만 (예 : 투명한 알림 오버레이가있는 경우) 보이지 않습니다. 그렇기 때문에이 답변을 업데이트했습니다.
포 그라운드에 아무것도없는 곳에서 활동을 전환 할 때 Android에 이상한 순간이 있다는 것을 아는 것이 중요합니다 . 이러한 이유로, 동일한 앱에서 액티비티간에 전환 할 때 애플리케이션이 포 그라운드에 있는지 확인하면 포 그라운드에 있지 않다는 메시지가 표시됩니다 (앱이 여전히 활성 앱이고 표시됨) ).
당신의 앱이 포 그라운드에있는 경우 확인할 수 있습니다 Activity
의 onPause()
방법 후 super.onPause()
. 내가 방금 말한 이상한 림보 상태를 기억하십시오.
이후Activity
의 onStop()
메소드 에서 앱이 표시되는지 (즉, 백그라운드에없는 경우) 확인할 수 있습니다 . super.onStop()
onStop()
후 super.onStop()
. 에서 배경을 확인하지 마십시오 onPause()
.
GOOGLE SOLUTION- 이전 솔루션처럼 해킹이 아닙니다. ProcessLifecycleOwner Kotlin 사용
:
class ArchLifecycleApp : Application(), LifecycleObserver {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded() {
// App in foreground
}
}
자바:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppForegrounded() {
// App in foreground
}
}
app.gradle에서
dependencies {
...
implementation "android.arch.lifecycle:extensions:1.1.0"
//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
}
allprojects {
repositories {
...
google()
jcenter()
maven { url 'https://maven.google.com' }
}
}
라이프 사이클 관련 아키텍처 구성 요소에 대한 자세한 내용은 여기 ( https://developer.android.com/topic/libraries/architecture/lifecycle)를 참조하십시오.
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
할 수 있습니다 . 그러면 다음과 같이 전경 상태를 얻을 수 있습니다.ArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, 이것은 multiple processes
앱에서 작동하지 않습니다. 우아하게 달성 할 수있는 API가 있습니까?
지원 라이브러리 버전 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);
Android API 16부터 앱이 포 그라운드에 있는지 확인하는 간단한 방법이 있습니다. 완벽하지는 않지만 안드로이드의 방법은 절대 아닙니다. 이 방법은 서비스가 서버로부터 업데이트를 수신 할 때 사용하기에 충분하며 알림 표시 여부를 결정해야합니다 (UI가 포 그라운드 인 경우 사용자는 알림없이 업데이트를 알 수 있음).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
JobService
서비스가 백그라운드에서 실행되고 있음을 감지 하기 위해이 코드를 사용할 수있었습니다 .
Idolon의 대답은 오류가 발생하기 쉽고 여기에서 안드로이드 응용 프로그램이 포 그라운드에 있는지 여부를 확인하는 것이 훨씬 더 복잡 합니까? 여기 백그라운드 작업이나 서비스에서 현재 전경 응용 프로그램을 결정
훨씬 더 간단한 접근 방식이 있습니다.
모든 활동이 확장 되는 BaseActivity에서 :
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
응용 프로그램 활동이 포 그라운드에 있는지 확인 해야 할 때마다 확인하십시오isVisible()
.
이 방법은 나란히 활동의 라이프 사이클이 답변을 확인 이해하려면 다음 작업을 나란히 라이프 사이클
Idolon's answer is error prone
불행히도 나는 당신의 의견에 동의해야합니다. Google 그룹스에서 Dianne Hackborn의 의견을 바탕으로 답변을 업데이트했습니다. 자세한 내용은 확인해주세요.
onPause
경우 onStop
, 및 onResume
이벤트가 호출 되지 않는 것 입니다. 이 이벤트 중 어느 것도 발생하지 않으면 어떻게해야합니까?!
Application.ActivityLifecycleCallbacks 및 기타 여러 가지 를 사용하는 권장 솔루션을 시도했지만 예상대로 작동하지 않았습니다. Sarge 덕분에 아래에서 설명하는 매우 쉽고 간단한 솔루션을 생각해 냈습니다.
그들은 솔루션의 핵심 우리가 ActivityA 및 ActivityB을 가지고 우리가 ActivityA에서 ActivityB를 호출하는 경우 (그리고 전화를하지 않는 것이 이해의 사실이다
ActivityA.finish
, 다음 ActivityB의)가onStart()
호출됩니다 전에 ActivityAonStop()
.
그것은 또한의 주요 차이 onStop()
와 onPause()
그 누구도 내가 읽은 기사에서 언급을하지 않았다.
따라서이 활동의 라이프 사이클 동작에 따라, 당신은 단순히 한 횟수를 셀 수 onStart()
와 onPause()
프로그램에서 호출되었다. 참고 각 Activity
프로그램의, 당신은 오버라이드 (override) 할 필요가 onStart()
및 onStop()
순서는, 증가 / 감소 정적 변수는 계산에 사용합니다. 아래는이 논리를 구현하는 코드입니다. 확장하는 클래스를 사용하고 Application
있으므로 간단한 사용자 정의 클래스를 사용하여 구현할 수도 있지만 Manifest.xml
Application 태그 내부 에서 선언하는 것을 잊지 마십시오 android:name=".Utilities"
.
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
이제 우리 프로그램의 각 활동에, 우리는 오버라이드 (override) onStart()
하고 onStop()
아래와 같이 및 증가 / 감소를 :
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void onStop()
{
Utilities.activityStopped();
if(Utilities.isApplicationOnBackground())
{
//you should want to check here if your application is on background
}
super.onStop();
}
이 논리를 사용하면 가능한 두 가지 경우가 있습니다.
stateCounter = 0
: 중지 된 수는 시작된 활동 수와 같습니다. 즉, 애플리케이션이 백그라운드에서 실행 중임을 의미합니다.stateCounter > 0
: 시작 횟수가 중지 횟수보다 많으므로 애플리케이션이 포 그라운드에서 실행 중임을 의미합니다.참고 : stateCounter < 0
시작하기보다는 중지 된 활동이 더 많음을 의미하므로 불가능합니다. 이 경우에는 카운터를 증가 / 감소시키지 않는 것입니다.
당신은 갈 준비가되었습니다. 애플리케이션이 백그라운드에 있는지 확인해야합니다 onStop()
.
if(Utilities.isApplicationOnBackground()) …
합니다 Utilities
. 그렇지 않으면 특정 활동 만 이벤트에 반응하기 때문입니다.
활동을 볼 수 있는지 여부를 판단 할 수있는 방법은 없습니다. 아마도 새로운 StackOverflow 질문을하여 사용자 경험을 통해 달성하려는 것이 무엇인지 설명해야하므로 대체 구현 아이디어를 제공 할 수 있습니다.
Service
. 그렇다면 활동이 서비스에 나타나고 사라짐을 알리도록하십시오. (가)되면 Service
어떤 활동을 볼 수 있다는 것을 결정하고, 그 시간의 일부 금액에 대한 그런 식으로 남아, 다음 논리적 인 정지 지점에서의 데이터 전송을 중지합니다. 예, 각 활동에 대한 코드가 필요하지만 현재 불가피한 AFAIK입니다.
MyActivityClass
에서 상속 Activity
하고 구현 하는 클래스를 작성하고 모든 활동이에서 상속되도록 할 수 있습니다 MyActivityClass
. 이에 대한 일 것이다 PreferenceActivity
또는 MapActivity
비록 (볼 이 질문에 )
ComponentCallbacks2 를 사용 하여 앱이 백그라운드에 있는지 감지 할 수 있습니다 . BTW이 콜백은 API 레벨 14 (Ice Cream Sandwich) 이상 에서만 사용할 수 있습니다 .
메소드를 호출합니다.
public abstract void onTrimMemory (int level)
레벨이 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
앱이면 백그라운드에 있습니다.
당신은이 인터페이스를 구현할 수 있습니다 activity
, service
등
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// app is in background
}
}
}
@Cornstalks를 기반으로 유용한 몇 가지 기능이 포함되어 있습니다.
추가 기능 :
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
내가 생각해 낸 최고의 솔루션은 타이머를 사용합니다.
onPause ()에서 타이머를 시작하고 onResume ()에서 동일한 타이머를 취소하면 Timer의 인스턴스가 하나 있습니다 (일반적으로 Application 클래스에 정의 됨). 타이머 자체는 2 초 후에 (또는 적절하다고 생각되는 간격으로) Runnable을 실행하도록 설정되며, 타이머가 실행될 때 응용 프로그램을 백그라운드로 표시하는 플래그를 설정합니다.
타이머를 취소하기 전에 onResume () 메서드에서 백그라운드 플래그를 쿼리하여 모든 시작 작업을 수행 할 수 있습니다 (예 : 다운로드 시작 또는 위치 서비스 사용).
이 솔루션을 사용하면 백 스택에서 여러 가지 활동을 수행 할 수 있으며 구현 권한이 필요하지 않습니다.
이 솔루션은 타이머가 단순히 이벤트를 발생시킬 수 있고 앱의 다양한 부분이 그에 따라 응답 할 수 있으므로 이벤트 버스를 사용하는 경우에도 효과적입니다.
개발자 활동을 "활동을 유지하지 마십시오"로 설정 한 경우 생성 된 활동 수만 검사하면 충분하지 않습니다. isSaveInstanceState 도 확인해야합니다 . 내 사용자 정의 메소드 isApplicationRunning () 확인은 Android 앱이 실행 중입니다.
여기 내 작업 코드 :
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
유일한 해결책은 다음과 같습니다.
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
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) {
...
}
}
}
CommonsWare 및 Key가 말한 내용을 피기 백하기 위해 Application 클래스를 확장하고 모든 활동이 onPause / onResume 메소드에서 호출되도록 할 수 있습니다. 이를 통해 어떤 활동이 보이는지 알 수 있지만 더 잘 처리 할 수 있습니다.
당신이 생각하고있는 것을 정확하게 설명 할 수 있습니까? 백그라운드에서 실행한다고 말하면 현재 화면에 나타나지 않아도 응용 프로그램이 여전히 메모리에 남아 있다는 의미입니까? 서비스가 초점이 맞지 않을 때 서비스를보다 지속적으로 관리하는 방법으로 서비스를 사용하고 있습니까?
Application
이없는 onPause()
나 onResume()
.
ActivityLifecycleCallbacks를 직접 구현했습니다. SherlockActivity를 사용하고 있지만 일반적인 활동 클래스에서는 작동 할 수 있습니다.
먼저, 활동 라이프 사이클을 추적하기위한 모든 메소드가있는 인터페이스를 작성 중입니다.
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
둘째, 내 응용 프로그램 클래스 에서이 인터페이스를 구현했습니다.
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
셋째, SherlockActivity에서 확장되는 클래스를 만들고 있습니다.
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
넷째, SherlockActivity에서 확장되는 모든 클래스는 MySherlockActivity로 대체되었습니다.
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
이제 logcat에 MyApplication에서 만든 인터페이스 구현에 프로그래밍 된 로그가 표시됩니다.
아직 언급되지 않았으므로 독자는 Android 아키텍처 구성 요소를 통해 사용 가능한 ProcessLifecycleOwner 를 탐색하도록 제안합니다.
시스템은 포 그라운드 앱과 백그라운드 앱을 구분합니다. (서비스 제한을위한 배경 정의는 메모리 관리에서 사용되는 정의와는 다릅니다. 앱은 메모리 관리 와 관련하여 백그라운드에있을 수 있지만 서비스를 시작하는 기능과 관련하여 포 그라운드에있을 수 있습니다.) 다음 중 하나에 해당하면 포 그라운드에있는 것으로 간주됩니다.
이러한 조건 중 어느 것도 해당되지 않으면 앱이 백그라운드에있는 것으로 간주됩니다.
이 오래된 게시물에 대한 또 다른 해결책 (도움이되는 사람들을위한) :
<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();
}
}
onActivityDestroyed 함수의 주석을 참조하십시오.
SDK 대상 버전 14에서 작동 :>
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
나는이 질문이 더 분명해야한다고 생각합니다. 언제? 어디? 앱이 백그라운드에있는 경우 확인하려는 특정 상황은 무엇입니까?
방금 내 솔루션을 소개합니다. 내 응용 프로그램 의 모든 활동 방법에서 클래스의
"중요도"필드를 사용 하여이 작업을 수행합니다. "중요도"의 값을 확인하는 방법을 구현하는 다른 활동을 확장 하여 간단히 얻을 수 있습니다 . 코드는 다음과 같습니다.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;
}
이 페이지를 읽는 것이 좋습니다. http://developer.android.com/reference/android/app/Activity.html
즉, 활동이 onStop()
호출 된 후에는 더 이상 활동이 표시되지 않습니다 .
onStop
; 사이 onPause
그리고 onStop
그건 볼 수 있지만 전경 .
onStop()
당신이 쓴 것과 일치 .
onPause
호출 할 때까지 : 최근 편집으로 수정했습니다.
제 생각에는 많은 답변이 많은 양의 코드를 도입하고 많은 복잡성과 가독성을 가져옵니다.
사람들이 SO Service
와 a 사이의 통신 방법을 물으면 Activity
일반적으로 LocalBroadcastManager 를 사용하는 것이 좋습니다 .
왜?
글쎄, 문서를 인용함으로써 :
브로드 캐스트하는 데이터가 앱을 떠나지 않으므로 개인 데이터 유출에 대해 걱정할 필요가 없습니다.
다른 응용 프로그램에서 이러한 브로드 캐스트를 앱으로 보낼 수 없으므로 악용 할 수있는 보안 허점에 대해 걱정할 필요가 없습니다.
시스템을 통해 글로벌 브로드 캐스트를 전송하는 것보다 효율적입니다.
문서에 없습니다.
Activity
, Application
...기술
따라서 Activity
현재 전경 에있는 것이 있는지 확인하고 싶습니다 . 당신은 보통 Service
또는 Application
수업 에서 그렇게합니다 .
즉, Activity
객체가 신호를 보내는 사람이됩니다 (켜짐 / 꺼짐). 여러분 Service
, 다른 한편으로는,이된다 Receiver
.
거기 두 의 순간은Activity
전경이나 배경으로 가고 있는지 알려주 (예 : 6이 아닌 2 개만).
Activity
포 그라운드로 갈 때 onResume()
메소드가 트리거됩니다 (또한onCreate()
).
(가) 때 Activity
뒤쪽에 간다,onPause()
라고합니다.
이것은 당신이 당신 Activity
의 신호를 보내야 할 순간입니다Service
상태를 설명 위해 .
여러 경우 Activity
의,은 An 기억Activity
이 먼저 백그라운드로 이동하고 다른 하나가 포 그라운드로 들어온 .
따라서 상황은 다음과 같습니다. *
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service
/는 Application
단순히 그 신호 대기를 유지하고 그에 따라 행동 할 것이다.
코드 (TLDR)
귀하는 Service
를 구현해야 BroadcastReceiver
신호를 수신하기 위해.
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
레지스터 Receiver
의를Service::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
등록 해제 Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
이제 귀하 Activity
의 상태를 알려야합니다.
에 Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
에 Activity::onPause()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
매우 일반적인 상황
개발자 : 내 데이터를 보내고을
Service
업데이트하고 싶습니다Activity
.Activity
가 전경에 있는지 어떻게 확인 합니까?
일반적으로 Activity
전경에 있는지 여부를 확인할 필요가 없습니다. LocalBroadcastManager
에서 를 통해 데이터를 보내 십시오 Service
. Activity
이 켜져 있으면 응답하고 작동합니다.
이 매우 일반적인 상황에서는 Service
발신자가되고 Activity
구현은을 구현합니다 BroadcastReceiver
.
따라서에을 만드 Receiver
십시오 Activity
. 에 등록하고 등록을 onResume()
취소하십시오 onPause()
. 다른 수명주기 방법을 사용할 필요가 없습니다 .
Receiver
동작을 정의하십시오 onReceive()
(ListView 업데이트,이 작업을 수행하십시오 ...).
이렇게 Activity
하면 전경에있는 경우에만 청취하고 뒤쪽에 있거나 파괴 된 경우 아무 일도 일어나지 않습니다.
여러 개의 경우 켜져있는 Activity
중 Activity
하나라도 응답합니다 (또한 구현 한 경우 Receiver
).
모두 배경에 있으면 아무도 응답하지 않고 신호가 손실됩니다.
신호 ID를 지정하여 Service
via 에서 데이터를 전송하십시오 Intent
(위 코드 참조).
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
Foreground 에 있는지 여부에 대한 논리를 포함하는 작은 유틸리티 클래스를 만들었습니다 .
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
}
}
}
내 활동 onResume 및 onPause에서 isVisible 부울을 SharedPrefences에 씁니다.
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
필요할 때 다른 곳에서 읽어보십시오.
// Show a Toast Notification if App is not visible (ie in background. Not running, etc)
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
if(!sharedPrefs.getBoolean("visible", true)){...}
아마 우아하지는 않지만 그것은 나를 위해 작동합니다 ...
대답하기에는 너무 늦을 수도 있지만 누군가가 방문하면 여기에 제안하는 해결책이 있습니다. 앱이 백그라운드에 있거나 전경에 오는 상태를 알고 싶어하는 이유는 많을 수 있습니다. 사용자가 BG에있을 때 토스트 및 알림을 표시합니다. 2. 설문 조사, 다시 그리기 등과 같이 사용자가 BG에서 처음 왔을 때 일부 작업을 수행하려면
Idolon 등의 솔루션은 첫 번째 부분을 처리하지만 두 번째 부분은 처리하지 않습니다. 앱에 여러 액티비티가 있고 사용자가 액티비티간에 전환하는 경우 두 번째 액티비티에있을 때 표시되는 플래그는 false입니다. 따라서 결정적으로 사용할 수 없습니다.
나는 CommonsWare가 제안한 것을 수행했다. "서비스가 가시적 인 활동이 없다고 판단하고 일정 시간 동안 그런 식으로 유지 되면 다음 논리적 중지 지점에서 데이터 전송을 중지하십시오."
굵은 선은 중요하며 두 번째 항목을 달성하는 데 사용할 수 있습니다. 그래서 내가하는 일은 일단 onActivityPaused ()를 얻고 가시성을 직접 false로 변경하지 않고 대신 3 초의 타이머 (다음 액티비티가 시작되어야하는 최대 값)를 가지며 onActivityResumed ( ) 다음 3 초 후에 호출하고 표시를 false로 변경하십시오. 마찬가지로 onActivityResumed ()에서 타이머가 있으면 취소합니다. 요약하면 보이는 것은 isAppInBackground입니다.
코드를 복사하여 붙여 넣을 수 없습니다 ...