所谓背景,指的是应用程序的所有活动当前对用户都不可见。
private static boolean isApplicationForeground(Context context) {
KeyguardManager keyguardManager =
(KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardLocked()) {
return false;
}
int myPid = Process.myPid();
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list;
if ((list = activityManager.getRunningAppProcesses()) != null) {
for (ActivityManager.RunningAppProcessInfo aList : list) {
ActivityManager.RunningAppProcessInfo info;
if ((info = aList).pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
}
return false;
}
private fun isApplicationForeground(context: Context): Boolean {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
if (keyguardManager.isKeyguardLocked) {
return false
}
val myPid = Process.myPid()
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
var list: List<ActivityManager.RunningAppProcessInfo>
if (activityManager.runningAppProcesses.also { list = it } != null) {
for (aList in list) {
var info: ActivityManager.RunningAppProcessInfo
if (aList.also { info = it }.pid == myPid) {
return info.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
}
}
return false
}
我认为这个问题应该更加清晰明了。什么时候?在哪里?你想知道的具体情况是什么,以便确定你的应用程序是否在后台运行?
我会用自己的方式来介绍我的解决方案。
我通过在每个活动的onStop
方法中使用RunningAppProcessInfo
类的"importance"字段来完成此操作,在其他活动中提供一个BaseActivity
来扩展,该活动实现onStop
方法以检查"importance"的值。以下是代码:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
Service
和Activity
之间通信时,我通常建议使用LocalBroadcastManager。
为什么?
好吧,引用文档:
您知道广播的数据不会离开您的应用程序,因此不需要担心泄漏私人数据。
其他应用程序无法向您的应用程序发送这些广播,因此您不需要担心它们可以利用的安全漏洞。
它比通过系统发送全局广播更有效率。
文档中没有提到的:
Activity
、Application
等上没有强引用描述
所以,您想要检查是否有任何Activity
当前在前台。通常情况下,您会在Service
或Application
类中执行此操作。
这意味着,您的Activity
对象成为信号的发送者(我在/我不在)。另一方面,您的Service
则成为接收器。
有两个时刻,您的Activity
告诉您它是进入前台还是后台(只有两个...不是6个)。
当Activity
进入前台时,将触发onResume()
方法(也称为onCreate()
之后调用)。
当Activity
进入后台时,将调用onPause()
。
这些是您的Activity
应向Service
发送信号以描述其状态的时刻。
如果有多个Activity
,请记住一个Activity
首先进入后台,然后另一个Activity
进入前台。
因此,情况将是:*
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
Service
/ Application
将会持续监听这些信号并相应地采取行动。
代码(简版)
你的Service
必须实现一个BroadcastReceiver
以便监听信号。
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
在 Service::onCreate()
中注册 Receiver
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
在Service::onDestroy()
中取消注册它。
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Activity
必须通知它们的状态。Activity::onResume()
中。Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
在Activity::onPause()
中
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
非常常见的情况
开发者:我想从我的
Service
发送数据并更新Activity
。如何检查Activity
是否在前台?
通常不需要检查Activity
是否在前台。只需通过LocalBroadcastManager
从您的Service
发送数据即可。如果Activity
正在运行,则它将响应并执行操作。
对于这种非常常见的情况,Service
成为发送方,而Activity
实现BroadcastReceiver
。
因此,在您的Activity
中创建一个Receiver
。在onResume()
中注册它,并在onPause()
中取消注册。 没有必要使用其他生命周期方法。
在onReceive()
中定义Receiver
的行为(更新ListView,执行此操作,执行那个操作等)。
这样Activity
只有在前台时才会监听,如果在后台或者被销毁就不会发生任何事情。
如果有多个Activity
,哪一个处于活跃状态就会响应(如果它们也实现了Receiver
)。
如果所有Activity
都在后台,则没有人会响应,信号将会被忽略。
通过指定信号ID通过Intent
从Service
发送数据(见上面的代码)。
另一个没有额外依赖的方法是这个:
只需将此方法添加到您的应用程序类中,并在 onCreate() 中调用它即可。
var isInBackground = true
private fun setupActivityLifecycleCallbacks() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {
isInBackground = false
}
override fun onActivityPaused(activity: Activity) {
isInBackground = true
}
override fun onActivityStopped(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
})
}
这样怎么样:
boolean isBackgrounded() {
try {
context.startService(new Intent(action));
return false;
}
catch (IllegalStateException exc) {
// "Not allowed to start service Intent: app is in background"
return true;
}
}
对于这篇旧帖子的另一个解决方案(对于那些可能有所帮助的人):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
使用 getApplicationState().isInForeground() 怎么样?
您应该使用共享首选项来存储属性,并使用服务绑定从您的活动中执行操作。如果仅使用绑定(即从未使用startService),则您的服务仅在绑定到它时运行(在onResume上绑定,在onPause上解除绑定),这将使其仅在前台运行,如果您确实想要在后台工作,则可以使用常规的启动停止服务。
@Override protected void onApplicationSentToBackground() { }
- Chuck D