如何检查活动是否在前台或可见后台?

126

我有一个基于计时器的启动屏幕。我的问题是在调用 finish() 方法之前,我需要检查下一个活动是否已经启动,因为系统会弹出一个对话框,我只想在用户选择对话框选项后才调用 finish() 方法。

我知道有很多问题是关于如何判断活动是否在前台运行,但我不确定这是否适用于位于活动顶部的对话框。

这是问题所在,红色表示我的活动在后台,而对话框在前台:

红色表示我的活动在后台,而对话框在前台

编辑: 我尝试过不使用 finish() 方法,但是这样我的活动会在应用程序栈中被保留,我要避免这种情况发生。


1
可能相关:https://dev59.com/OG855IYBdhLWcg3wUSgW - jarmod
为了澄清一下,您想要启动一个意图选择器,并在用户点击其中一个选项之后等待您的应用程序完成()吗?听起来您需要使用Intent.createChooser()和startActivityForResult(),然后在接收到结果后调用finish()。 - alanv
可能是检查Android应用程序是否在后台运行的重复问题 - Douglas Nassif Roma Junior
ProcessLifecycleOwner 是最新的解决方案。 - S.R
@AlexMisiulia 不,我会让投票说明一切——如果你的回答获得更多的赞同,我很乐意改变已接受的答案。 - Nick
@Nick,我明白你的观点。但问题是,已接受的答案存在缺陷,正如在评论中提到的那样,并且在某些情况下会工作不正确。更多的人会犯错并浪费时间。无论如何,这是你的选择) - Alex Misiulia
26个回答

0

你尝试过不调用finish方法,并在清单文件中添加android:noHistory="true"吗?这样可以防止该活动进入堆栈。


0

我必须说,你的工作流不符合标准的Android方式。在Android中,如果你想通过Intent打开另一个Activity,你不需要调用finish()方法关闭当前的Activity。为了方便用户,在Android中可以使用“返回键”从你打开的Activity返回到你的应用程序。

因此,只需要让系统停止你的Activity并保存需要保存的内容,当你的Activity被重新调用时就会自动恢复。


3
“buu this is not the android”方式的回答是令人厌烦的,而且回答并没有解决问题。此外,有合理的理由使用finish(); - 例如,一旦操作已经完成,返回到它可能毫无意义。换句话说,你认为他们加入finish()只是为了好玩吗?保持在堆栈中正是问题提出者想要避免的。 - Lassi Kinnunen
"不要再说这些无意义的回答了,这不是 Android 的方法。你的评论并不公平。虽然我指出了这不是 Android 的做法,但我在这句话之后给出了解答,而不是什么都没有给出。我只是没有用代码的形式给出答案,因为那样是不必要的。所以说我没有在一开始就回答问题是不公平的。" - Owen Zhao

0

既然你明确要求了一个Activity,我在我的Utils类中添加了一个简单的静态方法,通过传递该activity来获取activity的状态。

    public static boolean isActivityVisible(Activity mActivity) {
    if (mActivity != null) {
        Class klass = mActivity.getClass();
        while (klass != null) {
            try {
                Field field = klass.getDeclaredField("mResumed");
                field.setAccessible(true);
                Object obj = field.get(mActivity);
                return (Boolean)obj;
            } catch (NoSuchFieldException exception1) {
            Log.e(TAG, exception1.toString());
            } catch (IllegalAccessException exception2) {
            Log.e(TAG, exception2.toString());
            }
            klass = klass.getSuperclass();
        }
    }
    return false;
}

0

Activity内部使用这些方法。

isDestroyed()

添加于Api 17
如果最终的onDestroy()调用已经在Activity上执行,那么返回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
    }
  }
}

0
我发现了一种非常简单的方法来检查一个活动是在前台还是在后台。在我的情况下,我需要找到一种方法,在冷启动时只显示 com.google.android.gms.settings.ADS_PRIVACY 页面,以选择是否接受个性化广告;重置、启用或禁用广告标识符,该标识符根据加利福尼亚州、犹他州、俄勒冈州和美国的一些其他州的本地法律要求,影响我的应用程序的用户的消费者数据隐私/保护。我的解决方案是在 app.java 或 myApp.java 中创建一个全局变量。我只需要知道我的应用程序的启动菜单活动是否在后台运行,以防止在软启动期间显示设置页面,从其他活动打开启动菜单,关闭 appOpen 广告或关闭设置页面后恢复启动菜单活动。请参见下面的代码片段,其中包含了我的应用程序的 StartMenuActivity.java。希望对你有所帮助。
public class startMenuActivity extends AppCompatActivity {

    // other code snippets here
    // ...................

    boolean isAppInBackground;

    @Override
    protected void onCreate(Bundle SaveInstanceState) {
        super.onCreate(SaveInstanceState);
        setContentView(layout.start_menu);

        isAppInBackground = 
        ((myApp)this.getApplication()).getIsAppInBackground();
            if (!isAppInBackground) {
            showCCPAConsentDialog();
        }

        // other code snippets here
        // ...................
    }

    @Override
    protected void onStop() {
        Log.d("ACTIVITYSTAT", "StartMenuActivity is in the background");
        ((myApp)this.getApplication()).setIsAppInBackground(true);
        super.onStop();

    }

    @Override
    protected void onResume() {
        Log.d("ACTIVITYSTAT", "StartMenuActivity is in the foreground");
        /* code snippet for your global variable to indicate that your 
        app activity is in the foreground */
 
        super.onResume();
    }
}

-4

我以前的做法是,

如果活动不在前台

getIntent()

将返回 null。:=P


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接