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。希望您能找到更好的解决方案...请告诉我!!!
我有一个带有登录屏幕的应用程序。该应用程序还会在一定时间后注销用户。我使用 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。希望您能找到更好的解决方案...请告诉我!!!