Android 活动:如何区分关闭应用程序、更改方向和仅移动到背景

Android Activitiy: How can I get the difference between Close the app, Change the Orientation and just move to Background

我有一个带有登录屏幕的应用程序。该应用程序还会在一定时间后注销用户。我使用 AlarmManager 和 BroadcastReceiver 来执行此操作。 但是在我的 BroadcastReceiver.onReceive() 中,我需要知道我的应用程序是否在前台!!

我找到了这样的来源:

private boolean isAppInBackground(){
 boolean retValue = true;
 ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> runningProcesses = am.getRunningAppProcesses();
    for (ActivityManager.RunningAppProcessInfo processInfo : runningProcesses) {
        if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
            for (String activeProcess : processInfo.pkgList) {
                if (activeProcess.equals(context.getPackageName())) {
                    retValue = false;
                }
            }
        }
    }
 return retValue;
}

它适用于我的 API 21 设备...但它总是在我的 API 18 设备上带来错误!!

问题 1 是:我可以为 API18 设备做什么?

问题 2 是: 如果我使用此应用程序访问 PlayStore,我会被 Google 拒绝吗?? 因为Google说here

Note: this method is only intended for debugging or building a user-facing process management UI.

here 的一条评论说了一些来自 "reject"

的内容

更新:

更清楚一点: 例如,5 分钟后广播接收器得到 BroadcastReceiver.onReceive()。现在必须调用登录Activity,用户必须再次登录才能使用该应用程序。

但是如果用户在前台有我的应用 而不是(因为此时他正在使用地图或电子邮件)登录 Activity 不应在前台弹出,所以我在后台发送

moveTaskToBack(true);

但是我正在寻找一种方法来在 BroadcastReceiver.onReceive() 出现的那一刻清楚地找出我的应用程序是在后台还是在前台。

在您的应用程序中包含一些 EventBus。也许来自 GreenRobot.

在您的 BroadcastReceiver 中发送一个时间已过的事件,然后在您的 Activity 中注册该事件。如果某些 Activity 可见且处于活动状态 - 它将收到该事件,然后您可以注销您的用户。您不必检查您的应用程序是否在后台,因为当您在正确的时间从 EventBus 注册和取消注册您的 Activity 时,它们只会在它们在前台时做出反应。

注册取消注册的正确时间我的意思是 onResume 和 onPause 方法(或 onCreate/onDestroy)。

PS。使用此解决方案,您应该不会被 Play 商店拒绝。

经过多年的调查,我找到了解决我的特殊问题的方法。

受到 this Answer 的启发,你开始像这样使用 ActivityLifecycleCallbacks:

public class MyLifecycleHandler implements Application.ActivityLifecycleCallbacks {    
private static ActivityNames activityNameList = new ActivityNames();

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityDestroyed(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityResumed(Activity activity) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityPaused(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityStarted(Activity activity) {
    activityNameList.add(activity.getLocalClassName().hashCode());
}

@Override
public void onActivityStopped(Activity activity) {
    activityNameList.remove(activity.getLocalClassName().hashCode());
}

public static boolean isApplicationInBackground() {
    return activityNameList.isApplicationInBackground();
}

private static class ActivityNames {
    private List<Integer> nameList;

    void add(int value){
        if(nameList == null){
            nameList = new ArrayList<>();
        }

        if(nameList.contains(value)) return;

        nameList.add(value);
    }

     void remove(Integer value){
         if(nameList == null || nameList.size() < 1) return;
         nameList.remove(value);
     }

    boolean isApplicationInBackground(){
        if(nameList == null) return true;
        if(nameList.size() == 0) return true;

        return false;
    }
  }
}

我接收 AlarmManager 的 BroadcastReceiver 如下所示:

public class LogoutReceiver extends BroadcastReceiver {
   @Override
   public void onReceive(Context context, Intent intent) {
       ContextUtils.appIsInBackground = MyLifecycleHandler.isApplicationInBackground();
       EventBus.getDefault().post(new AutoLogoutEvent());
    }
}

ContextUtils() 只保留调用 Receiver 时的值以备后用。

AutoLogoutEvent() 被捕获并调用此 Intent 函数:

public void showAuthentication(Activity context) {

    Intent i = new Intent(context, LoginActivity.class);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        ContextUtils.appIsInBackground = false;
    }

    context.startActivity(i);
}

此处特别说明:Android KITKAT (API19) 之前的版本如果应用程序处于后台,则不会启动 Activity。所以我必须重新设置 ContextUtils.appIsInBackground 因为如果不是这样,你会尝试在 [=39= 的 onCreate() 这一刻将应用程序恢复到前台] 被调用但有错误的值,应用程序第一次没有出现在前台......你必须点击两次。这里是 Activity:

public class LoginActivity extends MosbyActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {        
       boolean appIsInBackground = false;

       appIsInBackground = ContextUtils.appIsInBackground;
       ContextUtils.appIsInBackground = false;

       if(appIsInBackground){
           moveTaskToBack(true);
       }

       super.onCreate(savedInstanceState);

       setContentView(R.layout.activity_login);

       if (savedInstanceState == null) {
           getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, new LoginFragment())
                .commit();
       }
   }

   ....
}

所以这适用于 ME。希望您能找到更好的解决方案...请告诉我!!!