활동이 전경 또는 보이는 배경에 있는지 확인하는 방법은 무엇입니까?
타이머에 스플래시 화면이 있습니다. 내 문제는 finish()
내 전에 시스템 대화 상자가 팝업되고 다음 작업 만 수행하기 때문에 다음이 시작된다는 것을 확인해야한다는 것입니다 finish()
. 사용자가 대화 상자에서 옵션을 선택하면?
활동이 전경에 있는지 확인하는 방법에 대한 많은 질문이 대화 상자를 알고 있는지도 모르겠습니다.
여기에 문제가 있습니다. 빨간색은 대화가 전경에있는 동안 배경에있는 내 활동입니다.
편집 : 나는 사용하지 finish()
않는 내 활동은 피하려고하는 응용 프로그램 스택으로 돌아갈 수 있습니다.
이것이 올바른 솔루션으로 권장되는을 구석으로입니다 .
올바른 솔루션 (신용은 Dan, CommonsWare 및 NeTeInStEiN으로 이동) Activity.onPause, Activity.onResume 메소드를 사용하여 애플리케이션 가시성을 직접 추적하십시오. 다른 클래스에 "가시성"상태를 저장합니다. 좋은 선택은 애플리케이션 또는 서비스의 자체 구현입니다 (서비스에서 활동 가시성을 확인하려는 경우이 솔루션의 몇 가지도 있습니다).
예제 사용자 지정 응용 프로그램 클래스를 구현합니다 (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을 추가합니다 (원하는 경우 활동에 대한 확장 조상을 만들 수 있습니다 활동이 이미 MapActivity / ListActivity 등에서 된 경우 계속 다음을 직접 작성해야합니다). :
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
귀하의 finish()
방법 isActivityVisible()
에서 활동이 표시 여부를 확인 합니다 . 사용자가 옵션을 선택했는지 여부를 확인할 수 있습니다. 두 조건이 모두 계속됩니다.
소스는 또한 두 가지 솔루션을 언급하지 않습니다.
출처 : stackoverflow
API 레벨 14 이상을 대상으로하는 경우 android.app.Application.ActivityLifecycleCallbacks 를 사용할 수 있습니다 .
public class MyApplication extends Application implements ActivityLifecycleCallbacks {
private static boolean isInterestingActivityVisible;
@Override
public void onCreate() {
super.onCreate();
// Register to be notified of activity state changes
registerActivityLifecycleCallbacks(this);
....
}
public boolean isInterestingActivityVisible() {
return isInterestingActivityVisible;
}
@Override
public void onActivityResumed(Activity activity) {
if (activity instanceof MyInterestingActivity) {
isInterestingActivityVisible = true;
}
}
@Override
public void onActivityStopped(Activity activity) {
if (activity instanceof MyInterestingActivity) {
isInterestingActivityVisible = false;
}
}
// Other state change callback stubs
....
}
UPD : 상태로 업데이트되었습니다 Lifecycle.State.RESUMED
. @htafoya 에게 감사드립니다 .
2019 년에는 새로운 지원 라이브러리 28+
또는 AndroidX의 도움으로 다음을 간단히 사용할 수 있습니다.
val isActivityInForeground = activity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
후드 아래에서 무슨 일이 일어 났는지 이해하기 위해 문서 에서 더 많은 것을 읽을 수 있습니다 .
이것이 바로 작업 문서에 클래스 설명 된 활동의 onPause
및 onStop
이벤트 간의 차이점 입니다.
내가 당신을 당신이 말하는 것을 이해한다면, 당신이하고 싶은 것은 당신 finish()
의 활동에서 전화 를 걸어 onStop
종료하는 것입니다. 활동 라이프 사이클 데모 앱 의 첨부 된 이미지를 참조하십시오 . 활동 B가 활동 A에서 시작될 때의 모습입니다. 이벤트 순서는 아래에서 위로 진행 onStop
활동 B onResume
가 이미 호출 된 후 활동 A 가 호출 할 수 있습니다 .
대화 상자가 표시되는 경우 활동이 배경에서 표시되고 onPause
호출됩니다.
Activity :: hasWindowFocus () 는 필요한 부울을 반환합니다.
public class ActivityForegroundChecker extends TimerTask
{
private static final long FOREGROUND_CHECK_PERIOD = 5000;
private static final long FIRST_DELAY = 3000;
private Activity m_activity;
private Timer m_timer;
public ActivityForegroundChecker (Activity p_activity)
{
m_activity = p_activity;
}
@Override
public void run()
{
if (m_activity.hasWindowFocus() == true) {
// Activity is on foreground
return;
}
// Activity is on background.
}
public void start ()
{
if (m_timer != null) {
return;
}
m_timer = new Timer();
m_timer.schedule(this, FIRST_DELAY, FOREGROUND_CHECK_PERIOD);
}
public void stop ()
{
if (m_timer == null) {
return;
}
m_timer.cancel();
m_timer.purge();
m_timer = null;
}
}
다음은 어디에서나 활동의 가시성을 확인하는 예제 클래스입니다.
대화 상자 를 표시하면 대화 상자 에 주요 포커스가 있기 때문에 결과는 거짓이됩니다. 그 외에는 제안 된 솔루션보다 정말 편리하고 수 있습니다.
두 가지 가능한 솔루션 :
1) 활동 라이프 사이클
ActivityLifecycleCallbacks 를 구현 하는 애플리케이션 을 사용하고이를 사용하여 애플리케이션 에서 활동 라이프 사이클 이벤트를 추적합니다. ActivityLifecycleCallbacks는 Android API> = 14 용입니다. 이전 Android API의 경우 모든 활동 내에서 직접 구현해야합니다 ;-)
활동에 적극적으로 주를 공유 / 저장해야 할 때 응용 프로그램을 사용하십시오 .
2) 실행중인 프로세스 정보 확인
이 클래스는 RunningAppProcessInfo를 사용하여 실행중인 프로세스의 상태를 확인할 수 있습니다.
ActivityManager.getRunningAppProcesses ()로 실행 중인 프로세스 목록을 가져 오고 결과 목록을 필터링하여 원하는 RunningAppProcessInfo를 확인하고 "중요도"를 확인합니다.
github app-foreground-background-listen 에 프로젝트를 만들었습니다.
매우 간단한 논리를 사용하고 모든 Android API 수준에서 잘 작동합니다.
일시 중지와 백그라운드에서 다시 시작 사이의 시간 간격을 사용하여 백그라운드에서 깨어 있는지 확인합니다.
맞춤 애플리케이션에서
private static boolean isInBackground;
private static boolean isAwakeFromBackground;
private static final int backgroundAllowance = 10000;
public static void activityPaused() {
isInBackground = true;
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (isInBackground) {
isAwakeFromBackground = true;
}
}
}, backgroundAllowance);
Log.v("activity status", "activityPaused");
}
public static void activityResumed() {
isInBackground = false;
if(isAwakeFromBackground){
// do something when awake from background
Log.v("activity status", "isAwakeFromBackground");
}
isAwakeFromBackground = false;
Log.v("activity status", "activityResumed");
}
BaseActivity 클래스에서
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
더 나은 솔루션이 생각합니다. MyApplication.activityResumed ();에서 빌드 할 수 있기 때문입니다. 모든 활동에 하나씩 확장합니다.
먼저 (CyberneticTwerkGuruOrc와 같은) 생성해야합니다.
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" >
그런 다음 ActivityBase 클래스를 만듭니다.
public class ActivityBase extends Activity {
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
}
마지막으로 새 활동을 생성 할 때 활동 대신 ActivityBase로 간단히 확장 할 수 있습니다.
public class Main extends ActivityBase {
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
}
나를 위해 그것은 당신이 ActivityBase에 의해 확장에 대해 기억해야하는 더 나은 방법입니다. 또한 기본 기본 기능을 확장 할 수 있습니다. 제 경우에는 서비스에 대한 포함을 추가하고 한 클래스의 네트워크에 대한 경고를 추가했습니다.
간단하게 전화하면됩니다.
MyApplication.isActivityVisible()
이 Application.ActivityLifecycleCallbacks 를 사용하여 쉽게 방법으로 달성 할 수 있습니다.
예를 들어 Activity 클래스 이름을 ProfileActivity로 사용하면 전경 또는 배경인지 확인할 수 있습니다.
우리는 먼저 확장하여 우리의 응용 프로그램 클래스를 만드는 데 필요한 응용 프로그램 클래스
구현하는
Application.ActivityLifecycleCallbacks
다음과 같이 내 응용 프로그램 클래스가 될 수 있습니다.
애플리케이션 클래스
public class AppController extends Application implements Application.ActivityLifecycleCallbacks {
private boolean activityInForeground;
@Override
public void onCreate() {
super.onCreate();
//register ActivityLifecycleCallbacks
registerActivityLifecycleCallbacks(this);
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
//Here you can add all Activity class you need to check whether its on screen or not
activityInForeground = activity instanceof ProfileActivity;
}
@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 boolean isActivityInForeground() {
return activityInForeground;
}
}
위 클래스의 재정의 방법 onActivityResumed 의 ActivityLifecycleCallbacks은
@Override
public void onActivityResumed(Activity activity) {
//Here you can add all Activity class you need to check whether its on screen or not
activityInForeground = activity instanceof ProfileActivity;
}
현재 화면에 모든 활동 인스턴스를 수있는 곳에서 위의 방법으로 당신의 활동이 화면에 있는지 확인하십시오.
manifest.xml에 애플리케이션 클래스 등록
<application
android:name=".AppController" />
위의 솔루션에 따라 날씨 활동이 전경 또는 배경인지 확인 확인해야 할 장소에서 다음 메소드를 호출하십시오.
AppController applicationControl = (AppController) getApplicationContext();
if(applicationControl.isActivityInForeground()){
Log.d("TAG","Activity is in foreground")
}
else
{
Log.d("TAG","Activity is in background")
}
finish를 호출하지 않고 매니페스트에 "android : noHistory ="true "를 넣었습니까? 이렇게하면 액티비티가 스택으로 이동하지 않습니다.
당신의 워크 플로우가 표준 안드로이드 방식이 아니라고 말해야합니다. Android에서는 finish()
의도 된 다른 활동을 열려있는 경우 활동이 필요하지 않습니다 . 사용자의 편의를 위해 Android에서는 사용자가 '뒤로'키를 사용하여 열어 본 활동에서 앱으로 갈 수 있습니다.
따라서 시스템이 활동을 중지하고 활동이 될 때 필요한 모든 것을 저장합니다.
앱의 활동이 화면에 표시되어 있고 다음과 같이 할 수 있습니다.
public class MyAppActivityCallbacks implements Application.ActivityLifecycleCallbacks {
private Set<Class<Activity>> visibleActivities = new HashSet<>();
@Override
public void onActivityResumed(Activity activity) {
visibleActivities.add((Class<Activity>) activity.getClass());
}
@Override
public void onActivityStopped(Activity activity) {
visibleActivities.remove(activity.getClass());
}
public boolean isAnyActivityVisible() {
return !visibleActivities.isEmpty();
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
@Override
public void onActivityStarted(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) {}
@Override
public void onActivityDestroyed(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}}
이 클래스의 싱글 톤을 만들고 같이 Application 인스턴스에 설정하면됩니다.
class App extends Application{
@Override
public void onCreate() {
registerActivityLifecycleCallbacks(myAppActivityCallbacks);
}
}
그런 다음 어디에서나 MyAppActivityCallbacks 인스턴스의 isAnyActivityVisible () 메소드를 사용할 수 있습니다!
일시 중지 또는 재개 된 경우 플래그를 저장하십시오. 재개 널 전경에 있음을 의미합니다.
boolean isResumed = false;
@Override
public void onPause() {
super.onPause();
isResumed = false;
}
@Override
public void onResume() {
super.onResume();
isResumed = true;
}
private void finishIfForeground() {
if (isResumed) {
finish();
}
}
한 가지 가능한 해결은 시스템 대화 상자를 표시하는 동안 플래그를 설정 한 다음 활동 수명주기의 onStop 메소드에서 플래그를 확인하고 true 인 경우 활동을 확인하는 것입니다.
예를 들어 시스템 대화 상자가 일부 버튼 클릭에 의해 트리거되는 경우 onclick 리스너는 다음과 같을 수 있습니다.
private OnClickListener btnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
CheckActivity.this.startActivity(Intent.createChooser(intent, "Complete action using"));
checkFlag = true; //flag used to check
}
};
활동 중단시 :
@Override
protected void onStop() {
if(checkFlag){
finish();
}
super.onStop();
}
왜 제공을 위해 방송을 사용하지 않습니까? 두 번째 활동 (가동이 필요한 활동)은 다음과 같은 로컬 브로드 캐스트를 보낼 수 있습니다.
//put this in onCreate(..) or any other lifecycle method that suits you best
//notice the string sent to the intent, it will be used to register a receiver!
Intent result = new Intent("broadcast identifier");
result.putString("some message");//this is optional
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(result);
그런 다음 스플래시 활동 유전자 재조합 코딩하십시오.
//this goes on the class level (like a class/instance variable, not in a method) of your splash activity:
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//kill activity here!!!
//mission accomplished!
}
};
두 번째 활동에서 브로드 캐스트를 듣기 위해 LocalBroadcastManager에 새 포함을 등록합니다.
//notice the string sent to the intent filter, this is where you tell the BroadcastManager which broadcasts you want to listen to!
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, new IntentFilter("broadcast identifier"));
"브로드 캐스트 식별자"문자열에 상수 또는 고급 리소스를 사용할 수 있습니다.
finish()
새로운 앱이 앱의 스택 (작업) 시작되는 것을에서 막기 위해 사용하는 경우, 새로운 앱을 시작할 Intent.FLAG_ACTIVITY_NEW_TASK
때 플래그 를 사용할 수 있으며 전혀 호출하지 않습니다 finish()
. 문서 에 따르면 이것은 "실행기"스타일 동작을 구현하는 데 사용되는 플래그입니다.
// just add this line before you start an activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
내부에서 설치 방법을 사용하십시오 Activity
.
isDestroyed()
Api 17에 추가됨
Activity에서 마지막 onDestroy () 호출이 수행 된 경우 true를 반환하는 인스턴스는 이제 죽습니다.
isFinishing()
Api 1에 추가됨
완료 ()를 호출했거나 다른 사람이 완료를 요청했기 때문에이 활동이 완료 프로세스에 있는지 확인합니다. onPause ()에서 활동이 일시 중지 중지되거나 제거됩니다.
에서 메모리 누수 문서
일반적인 실수 AsyncTask
는 호스트 Activity
(또는 Fragment
)에 대한 강력한 참조를 사용하는 것입니다 .
class MyActivity extends Activity {
private AsyncTask<Void, Void, Void> myTask = new AsyncTask<Void, Void, Void>() {
// Don't do this! Inner classes implicitly keep a pointer to their
// parent, which in this case is the Activity!
}
}
작업이 실행되는 동안 구성 변경이 발생하는 경우와 AsyncTask
같이 부모보다 쉽게 오래 지속될 수 있기 때문에이 문제 Activity
입니다.
수행하는 올바른 방법은 작업을 static
클래스 로 만들고 구축을 구축하지 않고 호스트 에 대한 약한 참조 를 유지하는 것입니다 Activity
.
class MyActivity extends Activity {
static class MyTask extends AsyncTask<Void, Void, Void> {
// Weak references will still allow the Activity to be garbage-collected
private final WeakReference<MyActivity> weakActivity;
MyTask(MyActivity myActivity) {
this.weakActivity = new WeakReference<>(myActivity);
}
@Override
public Void doInBackground(Void... params) {
// do async stuff here
}
@Override
public void onPostExecute(Void result) {
// Re-acquire a strong reference to the activity, and verify
// that it still exists and is active.
MyActivity activity = weakActivity.get();
if (activity == null
|| activity.isFinishing()
|| activity.isDestroyed()) {
// activity is no longer valid, don't do anything!
return;
}
// The activity is still valid, do main-thread stuff here
}
}
}
다음은 Application
클래스를 사용하는 솔루션 입니다.
public class AppSingleton extends Application implements Application.ActivityLifecycleCallbacks {
private WeakReference<Context> foregroundActivity;
@Override
public void onActivityResumed(Activity activity) {
foregroundActivity=new WeakReference<Context>(activity);
}
@Override
public void onActivityPaused(Activity activity) {
String class_name_activity=activity.getClass().getCanonicalName();
if (foregroundActivity != null &&
foregroundActivity.get().getClass().getCanonicalName().equals(class_name_activity)) {
foregroundActivity = null;
}
}
//............................
public boolean isOnForeground(@NonNull Context activity_cntxt) {
return isOnForeground(activity_cntxt.getClass().getCanonicalName());
}
public boolean isOnForeground(@NonNull String activity_canonical_name) {
if (foregroundActivity != null && foregroundActivity.get() != null) {
return foregroundActivity.get().getClass().getCanonicalName().equals(activity_canonical_name);
}
return false;
}
}
다음과 같이 사용할 수 있습니다.
((AppSingleton)context.getApplicationContext()).isOnForeground(context_activity);
활동에 대한 참조가 경우 활동의 정식 이름을 사용하는 경우 포 그라운드에 있는지 여부를 확인할 수 있습니다. 이 솔루션은 완벽하지 않습니다. 따라서 귀하의 의견을 환영합니다.
나는 왜 아무도 공유하지 않습니다. 활동 A에 대해 SharedPreference를 설정했습니다 (예 : onPause ()) :
SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0);
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean("is_activity_paused_a", true);
editor.commit();
활동 가시성을 추적하는 수있는 방법이라고 생각합니다.
겠습니까 여기에 도움이 될까요? 거기에 더해 클래스 레벨 플래그 ( 그 세트 와 같은 것)를 사용하면 활동의 어느 시점에서든 점점이 맞춰져 있는지 여부를 알 수 있습니다. 문서를 알림 보면 대화 상자가 표시되거나 알림 읽어가 아래로 어울리는 것과 같이 활동이 물리적 "전경"에 직접 있지 않은 트레이 모든 상황에서 "거짓"으로 표시되는 설정되는 것처럼 보입니다.Activity.onWindowFocusChanged(boolean hasFocus)
isFocused
onWindowFocusChanged
예 :
boolean isFocused;
@Override
void onWindowFocusChanged (boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
isFocused = hasFocus;
}
void someMethod() {
if (isFocused) {
// The activity is the foremost object on the screen
} else {
// The activity is obscured or otherwise not visible
}
}
나는 좋아했었다.
활동이 포 그라운드에 있지 않은 경우
getIntent ()
null을 반환합니다. : = P
'IT' 카테고리의 다른 글
컴파일러 오류 : memset (0) | 2020.08.24 |
---|---|
stdClass () [duplicate]를 사용하여 배열을 객체로 변환하는 방법 (0) | 2020.08.24 |
C ++ 매크로를 사용하는 선행 변수 (0) | 2020.08.24 |
Android 휴대 전화 애플리케이션을 세로 모드로 잠금 (0) | 2020.08.24 |
Intellij에서 생성 된 버전 UID를 생성하는 방법 (0) | 2020.08.24 |