Android Activitiy:如何在关闭应用程序,更改方向和仅移至背景之间找到区别

时间:2015-09-17 12:05:07

标签: android broadcastreceiver android-lifecycle

我有一个带有LoginScreen的应用程序。该应用程序还会在一段时间后注销用户。我使用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的拒绝? 因为谷歌说here

  

注意:此方法仅用于调试或构建面向用户的流程管理UI。

来自here的一条评论说“拒绝”

更新

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

但如果用户在Foreground中有我的应用程序(因为他此时正在使用地图或电子邮件),则不应在Foreground中弹出登录活动,因此我将其发送到背景中

moveTaskToBack(true);

但是,当BroadcastReceiver.onReceive()出现时,我想找到一种方法来清楚地找出我在后台或前景中的应用程序。

2 个答案:

答案 0 :(得分:0)

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

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

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

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

答案 1 :(得分:0)

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

灵感来自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以供日后使用时,只需保留Moment中的值。

捕获

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);
}

特别之处:如果应用程序处于后台,则KITKAT(API19)之前的Android版本无法启动活动。所以我必须设置回 ContextUtils.appIsInBackground ,因为如果不是这样,并且你试图在这个时刻将应用程序返回到前景,则调用Activity的onCreate()但是具有错误的值并且应用程序第一次来到Foreground ...你必须点击两次。这里的活动:

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 。愿你找到更好的解决方案......请让我知道!!!