如何检查活动是在前景还是在可见的背景?
我有一个计时器的启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类文档中所描述的onPause
和onStop
事件之间的区别。
如果我正确地理解了你,你想要做的是从你的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(如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; }
接下来,您必须将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