Android 应用程序,Activity 状态(运行,不是 运行,前景/背景)
Android App, Activity State (Running, Not Running, Foreground/ Background)
我遇到了一个需求,但我无法获得正确的实现方式,因此需要您的帮助。
我想做什么? - 我想根据收到的通知执行操作,如下所示:
- 当应用程序打开并在前台时,即用户可见并且我收到通知时,我只是显示一个弹出窗口来启动我的 Activity B
- 当应用程序关闭时,即既不在后台也不在前台,我收到通知我将先启动我的应用程序,然后再启动 Activity B
- 当应用程序 运行 但在后台时,即在最近但用户不可见时,我想启动我的 Activity B 而无需重新启动应用程序。此外,在这种情况下,当用户按回 Activity B 时,他们应该在将其发送到后台之前看到他们离开的屏幕。
我做了什么?
我已经达到了第 1 点和第 2 点。我想达到第 3 点。我试过以下
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
然而,这 returns 在第 2 点和第 3 点这两种情况下都是正确的,所以我无法仅区分第 3 点。
我也尝试了下面的每一个 Activity 我有,
@Override
protected void onPause() {
super.onPause();
saveIsPausedInPref(true);
}
@Override
protected void onResume() {
super.onResume();
saveIsPausedInPref(false);
}
但是,它也不会给出所需的结果,因为如果通过按主页按钮将应用程序发送到后台,我的首选项将具有 isPaused = true 并且如果用户从最近删除应用程序然后它将保持真实,当通知到达时我将无法区分第 2 点和第 3 点。
对整个故事表示歉意,但我希望我能够解释我的要求。
提前致谢。 :)
编辑:
<activity
android:name=".HomeActivity"
android:screenOrientation="portrait" >
</activity>
<activity
android:name=".ChatProfileActivity"
android:screenOrientation="portrait" >
</activity>
我知道你已经弄清楚了 1 和 2,但我自己的想法不正确,以防你做了其他事情并且想看一看。
如何知道您的应用程序是否在前台?
- 使用堆栈在特定 activity 启动应用程序?
看一眼
TaskStackBuilder
有了这个
answer,
它将提供如何正确执行此操作的信息。
- 在保留当前堆栈的情况下恢复具有特定 activity 的应用程序?
使用回调检查应用程序的状态,然后在收到通知时打开 activity without FLAG_ACTIVITY_NEW_TASK。这应该做 tricl。
如果您更改为不显示任何弹出窗口,只是为了始终转到 Activity B(已销毁,背景或前景),则不需要任何此检查。
只是为了在您的通知中使用标志 FLAG_ACTIVITY_X(这是 GCM 这个通知?)。
您可以使用 onNewIntent 方法检查意图是否来自通知并启动 Activity B.
下面的代码适合我
在AndroidManifest.xml
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name=".MyApplication"
>
MyApplication.java
public class MyApplication extends Application {
private ActivityLifecycleCallbacks myLifecycleHandler;
@Override
public void onCreate() {
super.onCreate();
myLifecycleHandler=new MyLifecycleHandler();
registerActivityLifecycleCallbacks(myLifecycleHandler);
}
}
MyLifecycleHandler.java
public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private static final String TAG = MyLifecycleHandler.class.getSimpleName();
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
Log.d(TAG, "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
Log.d(TAG, "application is visible: " + (started > stopped));
}
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
}
现在使用 myLifecycleHandler 方法,您可以获得所需的所有状态。
isApplicationInForeground 表示 -> 至少一个 activity 处于可见状态。
isApplicationVisible 表示 -> 至少有一个 activity 已启动但未停止,表示应用程序处于 运行 状态
如果 isApplicationInForeground 为真 isApplicationVisible 将始终为真,但反之则不为真
要区分案例 #2 和案例 #3,您可以执行以下操作:
如果不是情况 #1,则启动 ActivityB
。在 ActivityB.onCreate()
中执行此操作:
super.onCreate(...);
if (isTaskRoot()) {
// ActivityB has been started when the app is not running,
// start the app from the beginning
Intent restartIntent = new Intent(this, MyRootActivity.class);
startActivity(restartIntent);
finish();
return;
}
... rest of onCreate() code here...
我遇到了一个需求,但我无法获得正确的实现方式,因此需要您的帮助。
我想做什么? - 我想根据收到的通知执行操作,如下所示:
- 当应用程序打开并在前台时,即用户可见并且我收到通知时,我只是显示一个弹出窗口来启动我的 Activity B
- 当应用程序关闭时,即既不在后台也不在前台,我收到通知我将先启动我的应用程序,然后再启动 Activity B
- 当应用程序 运行 但在后台时,即在最近但用户不可见时,我想启动我的 Activity B 而无需重新启动应用程序。此外,在这种情况下,当用户按回 Activity B 时,他们应该在将其发送到后台之前看到他们离开的屏幕。
我做了什么? 我已经达到了第 1 点和第 2 点。我想达到第 3 点。我试过以下
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
然而,这 returns 在第 2 点和第 3 点这两种情况下都是正确的,所以我无法仅区分第 3 点。
我也尝试了下面的每一个 Activity 我有,
@Override
protected void onPause() {
super.onPause();
saveIsPausedInPref(true);
}
@Override
protected void onResume() {
super.onResume();
saveIsPausedInPref(false);
}
但是,它也不会给出所需的结果,因为如果通过按主页按钮将应用程序发送到后台,我的首选项将具有 isPaused = true 并且如果用户从最近删除应用程序然后它将保持真实,当通知到达时我将无法区分第 2 点和第 3 点。
对整个故事表示歉意,但我希望我能够解释我的要求。
提前致谢。 :)
编辑:
<activity
android:name=".HomeActivity"
android:screenOrientation="portrait" >
</activity>
<activity
android:name=".ChatProfileActivity"
android:screenOrientation="portrait" >
</activity>
我知道你已经弄清楚了 1 和 2,但我自己的想法不正确,以防你做了其他事情并且想看一看。
如何知道您的应用程序是否在前台?
- 使用堆栈在特定 activity 启动应用程序? 看一眼 TaskStackBuilder 有了这个 answer, 它将提供如何正确执行此操作的信息。
- 在保留当前堆栈的情况下恢复具有特定 activity 的应用程序? 使用回调检查应用程序的状态,然后在收到通知时打开 activity without FLAG_ACTIVITY_NEW_TASK。这应该做 tricl。
如果您更改为不显示任何弹出窗口,只是为了始终转到 Activity B(已销毁,背景或前景),则不需要任何此检查。 只是为了在您的通知中使用标志 FLAG_ACTIVITY_X(这是 GCM 这个通知?)。
您可以使用 onNewIntent 方法检查意图是否来自通知并启动 Activity B.
下面的代码适合我
在AndroidManifest.xml
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name=".MyApplication"
>
MyApplication.java
public class MyApplication extends Application {
private ActivityLifecycleCallbacks myLifecycleHandler;
@Override
public void onCreate() {
super.onCreate();
myLifecycleHandler=new MyLifecycleHandler();
registerActivityLifecycleCallbacks(myLifecycleHandler);
}
}
MyLifecycleHandler.java
public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private static final String TAG = MyLifecycleHandler.class.getSimpleName();
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
Log.d(TAG, "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void onActivityStopped(Activity activity) {
++stopped;
Log.d(TAG, "application is visible: " + (started > stopped));
}
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
}
现在使用 myLifecycleHandler 方法,您可以获得所需的所有状态。
isApplicationInForeground 表示 -> 至少一个 activity 处于可见状态。
isApplicationVisible 表示 -> 至少有一个 activity 已启动但未停止,表示应用程序处于 运行 状态
如果 isApplicationInForeground 为真 isApplicationVisible 将始终为真,但反之则不为真
要区分案例 #2 和案例 #3,您可以执行以下操作:
如果不是情况 #1,则启动 ActivityB
。在 ActivityB.onCreate()
中执行此操作:
super.onCreate(...);
if (isTaskRoot()) {
// ActivityB has been started when the app is not running,
// start the app from the beginning
Intent restartIntent = new Intent(this, MyRootActivity.class);
startActivity(restartIntent);
finish();
return;
}
... rest of onCreate() code here...