我的计时器上有启动画面。我的问题是,在finish()
我进行活动之前,我需要检查下一个活动是否已经开始,因为会弹出一个系统对话框,而我只想这样做finish()
。一旦用户从对话框中选择了一个选项?
我知道关于如何查看您的活动是否在前台有很多问题,但是我不知道这是否也允许在活动顶部显示对话框。
这是问题所在,红色是我的活动,而背景是对话,而红色是我的活动:
编辑:我已经尝试过不使用,finish()
但是我的活动可以回到我试图避免的应用程序堆栈中。
我的计时器上有启动画面。我的问题是,在finish()
我进行活动之前,我需要检查下一个活动是否已经开始,因为会弹出一个系统对话框,而我只想这样做finish()
。一旦用户从对话框中选择了一个选项?
我知道关于如何查看您的活动是否在前台有很多问题,但是我不知道这是否也允许在活动顶部显示对话框。
这是问题所在,红色是我的活动,而背景是对话,而红色是我的活动:
编辑:我已经尝试过不使用,finish()
但是我的活动可以回到我试图避免的应用程序堆栈中。
Answers:
建议将以下建议作为正确的解决方案:
正确的解决方案(贷记给Dan,CommonsWare和NeTeInStEiN)可以使用Activity.onPause,Activity.onResume方法自己跟踪应用程序的可见性。将“可见性”状态存储在其他一些类中。好的选择是您自己的应用程序或服务的实现(如果您想检查服务的活动可见性,则此解决方案也有一些变体)。
示例 实现自定义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(如果您愿意,可以为您的Activity创建一个共同的祖先,但是如果您的Activity已经从MapActivity / ListActivity等扩展了,您仍然需要手工编写以下内容) :
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
在您的finish()
方法中,您想用来isActivityVisible()
检查活动是否可见。您还可以在此处检查用户是否选择了一个选项。满足两个条件时继续。
消息人士还提到了两个错误的解决方案...因此请避免这样做。
资料来源:stackoverflow
onPause
,onStop
也不该onResume
事件被调用。那么,如果这些事件均未触发,您该怎么办?
如果定位到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 :: 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;
}
}
这是一个示例类,可从任何地方检查活动的可见性。
请记住,如果显示对话框,则结果将为false,因为对话框将成为主要焦点。除此之外,它真的很方便,并且比建议的解决方案更可靠。
正如Activity类文档中所述,这恰好是ActivityonPause
和onStop
事件之间的区别。
如果我对您的理解正确,那么您想要做的就是finish()
从活动中致电onStop
以终止该活动。请参阅活动生命周期演示应用程序的附件图像。这是从活动A启动活动B时的样子。事件的顺序是从下到上,因此您可以看到在已经调用onStop
活动B之后调用了活动A。onResume
如果显示对话框,则您的活动在后台变暗并且仅onPause
被调用。
使用实现ActivityLifecycleCallbacks的应用程序并使用它来跟踪应用程序中的“活动”生命周期事件。请注意,ActivityLifecycleCallbacks适用于> = 14的Android api。对于以前的Android api,您需要在所有活动中自行实现;-)
需要共享/存储各个活动的状态时,请使用“ 应用程序”。
您可以使用此类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;
}
接下来,您必须将Application类添加到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();
}
}
最后,创建新的Activity时,可以简单地通过ActivityBase而不是Activity对其进行扩展。
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
如下所示作为我的Application类
应用类别
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;
}
}
在上面的类有一个覆盖methord 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类
<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")
}
如果您想知道您的应用程序的任何活动在屏幕上是否可见,可以执行以下操作:
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()方法!
我必须说您的工作流程不是标准的Android方式。在Android中,finish()
如果您想从Intent中打开另一个活动,则不需要活动。为了方便用户,Android允许用户使用“后退”键从您打开的活动返回到应用程序。
因此,只要让系统停止您的活动并在调用活动时保存一切即可。
一种可能的解决方案可能是在显示系统对话框时设置标志,然后在活动生命周期的onStop方法中检查标志(如果为true),以完成活动。
例如,如果系统对话框是由某些buttonclick触发的,则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"));
注意,您可以将常量或字符串资源用于“广播标识符”字符串。
LocalBroadcastManager
这里
如果您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中添加。
检查此活动是否正在完成中,这是因为您在此活动上调用了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
,例如,如果在任务运行时发生配置更改。
正确的方法是使您的任务成为一个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);
如果您对必需的活动具有引用,或者使用该活动的规范名称,则可以查明该活动是否在前台。此解决方案可能并非万无一失。因此,欢迎您提出意见。
会Activity.onWindowFocusChanged(boolean hasFocus)
是有用的吗?那个,加上一个类级别的标志,像isFocused
这样onWindowFocusChanged
设置,将是一种很容易的方法,可以在活动的任何时候告诉活动是否集中。通过阅读文档,在活动未直接位于物理“前景”中的任何情况下(例如正在显示对话框或下拉通知栏),它似乎都可以正确设置为“ false”。
例:
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
}
}