如何检查活动是在前景还是在可见的背景?

我有一个计时器的启animation面。 我的问题是,在我finish()我的活动之前,我需要检查下一个活动已经开始,因为系统对话框popup,我只想finish() ; 一旦用户从对话框中select了一个选项?

我知道如何看待你的活动是否在前台有很多问题,但我不知道这是否允许在活动之上的对话框。

这是问题,红色是我在后台进行的活动,而对话是在前台:

红色是我在背景中的活动,而对话是在前台

编辑:我试过只是不使用finish()但然后我的活动可以回到我试图避免的应用程序的堆栈。

这是build议作为正确的解决scheme:

正确的解决scheme(学分转到Dan,CommonsWare和NeTeInStEiN)使用Activity.onPause,Activity.onResume方法跟踪您的应用程序的可见性。 将“可见度”状态存储在其他一些类中。 好的select是你自己实现的应用程序或服务(如果你想检查服务的活动可见性,这个解决scheme也有一些变化)。

示例实现自定义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(如果您愿意,可以为您的活动创build一个共同的祖先,但是如果您的活动已经从MapActivity / ListActivity等扩展了,则仍然需要手动编写以下内容) :

 @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } 

finish()方法中,要使用isActivityVisible()来检查活动是否可见。 在那里,你也可以检查用户是否select了一个选项。 当两个条件都满足时继续。

来源还提到两个错误的解决scheme…所以避免这样做。

来源: 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 .... } 

这正是Activity类文档中所描述的onPauseonStop事件之间的区别。

如果我正确地理解了你,你想要做的是从你的activity onStop调用finish()来终止它。 请参阅活动生命周期演示应用程序的附加图像。 这就是从Activity A启动Activity B时的样子。事件的顺序是从下到上的,所以您可以看到Activity B onResume已经被调用后,Activity A onStop被调用。

活动生命周期演示

在显示对话框的情况下,您的活动在后台变暗,只有onPause被调用。

两种可能的解决方

1)活动LifeCyclecallback

使用实现ActivityLifecycleCallbacks的应用程序 ,并使用它来跟踪应用程序中的活动生命周期事件。 请注意,ActivityLifecycleCallbacks适用于Android api> = 14.对于之前的Android api,您需要在您的所有活动中自行实施它;-)

在需要共享/存储活动状态时使用应用程序 。

2)检查运行过程信息

您可以使用此类RunningAppProcessInfo检查正在运行的进程的状态

使用ActivityManager.getRunningAppProcesses()获取正在运行的进程列表并筛选结果列表以检查所需的RunningAppProcessInfo并检查其“重要性”

我已经在github app-foreground-background-listen上创build项目

它使用非常简单的逻辑,并与所有的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(); } 

你是否尝试过不完成,并在清单中放置“android:noHistory =”true?这将阻止活动进入堆栈。

我不得不说你的工作stream程不是以标准的Android方式。 在Android中,如果要从Intent中打开另一个活动,则不需要finish()您的活动。 至于用户的方便,Android允许用户使用“返回”键从您打开的应用程序返回。

所以只要让系统停止你的活动,并保存活动callback时所需的任何内容。

我想我有更好的解决办法。 因为你可以简单地构buildMyApplication.activityResumed(); 到每一个活动的一个延伸。

首先你必须创build(如Cyber​​neticTwerkGuruOrc)

 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; } 

接下来,您必须将Application类添加到AndroidManifest.xml

 <application android:name="your.app.package.MyApplication" android:icon="@drawable/icon" android:label="@string/app_name" > 

然后,创build类ActivityBase

 public class ActivityBase extends Activity { @Override protected void onPause() { super.onPause(); MyApplication.activityPaused(); } @Override protected void onResume() { super.onResume(); MyApplication.activityResumed(); } } 

最后,当您创build新的Activity时,您可以简单地通过ActivityBase而不是Activity来扩展它。

 public class Main extends ActivityBase { @Override protected void onResume() { super.onResume(); } @Override protected void onPause() { super.onPause(); } } 

对我来说这是更好的方法,因为你必须记住ActivityBase的扩展。 此外,您可以在将来扩展您的基本function。 在我的情况下,我添加了我的服务接收器,并在一个类的警报networking。

如果你想检查你的应用程序的可见性,你可以直接打电话

 MyApplication.isActivityVisible() 

如果您暂停或恢复,请保存一个标志。 如果你恢复,这意味着你在前台

 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(); } } 

一个可能的解决scheme可能是在显示系统对话框的同时设置一个标志,然后在活动生命周期的onStop方法中检查标志,如果为true,则完成活动。

例如,如果系统对话框是由某个button点击触发的,那么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")); 

请注意,您可以为“广播标识符”string使用常量或string资源。

如果使用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); 

这可以通过使用Application.ActivityLifecycleCallbacks来实现

例如,让我们把Activity的类名作为ProfileActivity让我们find它的前台还是后台

首先我们需要通过扩展Application Class来创build我们的应用程序类

实现

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; } } 

在上面的类中有一个ActivityActivityResumed的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; } 

可以find当前在屏幕上显示的所有活动实例,只需通过上述方法检查您的活动是否在屏幕上。

在manifest.xml中注册您的Application类

 <application android:name=".AppController" /> 

要检查天气活动是前景或背景按照上述解决scheme在需要检查的地方调用以下方法

 AppController applicationControl = (AppController) getApplicationContext(); if(applicationControl.isActivityInForeground()){ Log.d("TAG","Activity is in foreground") } else { Log.d("TAG","Activity is in background") } 

在一个Activity使用这些方法。

isDestroyed()

在Api 17中添加
如果在Activity上做了最后的onDestroy()调用,则返回true,所以这个实例现在已经死了。

isFinishing()

在Api 1中添加
检查这个活动是否正在完成,或者是因为你调用了finish()或者有人要求完成。 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 ,例如,如果在任务运行时发生configuration更改。

要做到这一点的正确方法是让你的任务成为一个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类的解决scheme。

 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); 

如果您有对所需活动的引用或使用活动的规范名称,则可以了解它是否在前台。 这个解决scheme可能不是万无一失的。 所以你的意见是真的欢迎。

我不知道为什么没有人谈论sharedPreferences,对于活动A,像这样设置SharedPreference(例如onPause()):

 SharedPreferences pref = context.getSharedPreferences(SHARED_PREF, 0); SharedPreferences.Editor editor = pref.edit(); editor.putBoolean("is_activity_paused_a", true); editor.commit(); 

我认为这是跟踪活动可视性的可靠方法。

我曾经喜欢,

如果活动不在前台

getIntent()

将返回null。 := P