所谓后台,我的意思是应用程序的活动目前对用户都不可见?
当前回答
在我看来,许多答案引入了大量的代码,带来了很多复杂性和可读性。
当人们问SO如何在服务和活动之间通信时,我通常建议使用LocalBroadcastManager。
Why?
我引用一下医生的话:
你知道你广播的数据不会离开你的应用程序,所以不需要担心泄露私人数据。 其他应用程序不可能将这些广播发送到你的应用程序,所以你不需要担心他们可以利用的安全漏洞。 这比通过系统发送全球广播更有效。
文档里没有:
它不需要外部库 代码是最少的 它易于实现和理解 没有自定义的自实现回调/超单例/进程内 任何模式…… 没有对Activity, Application,…
描述
你想要检查是否有Activity当前在前台。您通常在服务或应用程序类中这样做。
这意味着,您的Activity对象成为信号的发送者(I'm on / I'm off)。另一方面,您的服务成为接收者。
Activity有两个时刻告诉你它是在前台还是在后台(是的,只有两个…不是6)。
当Activity进入前台时,onResume()方法被触发(也在onCreate()之后调用)。
当Activity回到后面时,onPause()被调用。
在这些时刻,您的活动应该向您的服务发送信号,以描述其状态。
在有多个Activity的情况下,记住一个Activity先进入后台,然后另一个进入前台。
所以情况是:*
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
服务/应用程序将简单地监听这些信号并进行相应的操作。
代码(TLDR)
你的服务必须实现一个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")
在服务中注册接收者::onCreate()
@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必须传达它们的状态。
在活动::onResume ()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
在活动::onPause ()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
这是一种非常非常常见的情况
开发人员:我想从我的服务发送数据并更新活动。我如何检查活动是否在前景?
通常不需要检查Activity是否在前台。只需从服务中通过LocalBroadcastManager发送数据。如果活动处于开启状态,那么它将做出响应并采取行动。
对于这种非常常见的情况,服务成为发送方,活动实现BroadcastReceiver。
因此,在您的活动中创建一个Receiver。在onResume()中注册,在onPause()中取消注册。不需要使用其他生命周期方法。
在onReceive()中定义Receiver行为(更新ListView,做这个,做那个,…)
这样Activity只会在它在前台的时候监听,如果它在后面或者被销毁了什么也不会发生。
在多个活动的情况下,任何一个活动都将响应(如果它们也实现了Receiver)。
如果所有人都在后台,没有人会回应,信号就会丢失。
通过Intent(见上面的代码)通过指定信号ID从服务发送数据。
除了多窗口支持。这可能很棘手(如果需要,请测试它)…
其他回答
我想出的最好的解决办法是使用计时器。
你已经在onPause()中启动了一个定时器,并在onResume()中取消了相同的定时器,有一个定时器的实例(通常在应用程序类中定义)。计时器本身被设置为在2秒后(或您认为合适的任何时间间隔)运行Runnable,当计时器触发时,您设置一个标志,将应用程序标记为在后台。
在取消定时器之前的onResume()方法中,您可以查询后台标志来执行任何启动操作(例如开始下载或启用位置服务)。
这个解决方案允许您在back堆栈上有几个活动,并且不需要任何权限来实现。
如果你也使用事件总线,这个解决方案也很有效,因为你的计时器可以简单地触发一个事件,应用程序的各个部分可以相应地做出响应。
简单直接的回答:
override fun onPause() {
Log.i("APP LIFECYCLE", "App Enter BACKground")
isForeground = false
super.onPause()
}
override fun onResume() {
Log.i("APP LIFECYCLE", "App Enter FOREground")
isForeground = true
super.onResume()
}
然后只需使用您的活动的isForeground属性来检查状态。
根据CommonsWare和Key所说的,你可以扩展Application类,并让你所有的活动在onPause/onResume方法上调用它。这将允许您知道哪些活动是可见的,但这可能会得到更好的处理。
你能详细说明一下你的想法吗?当你说在后台运行,你的意思是简单地让你的应用程序仍然在内存中,即使它目前不在屏幕上?你有没有考虑过使用服务作为一种更持久的方式来管理你的应用程序,当它不在焦点?
这样怎么样:
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;
}
}
如果你打开开发人员设置“不要保留活动”-只检查创建的活动数量不够。您还必须检查isSaveInstanceState。我的自定义方法isApplicationRunning()检查android应用程序是否正在运行:
下面是我的工作代码:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件