Android 如果我关闭活动,则从BroadcastReceiver.onReceive调用peekService将返回null 问题
我为安卓4.3编写了一个程序,包含一个主活动、一个广播接收器和一个服务。活动通过其Android 如果我关闭活动,则从BroadcastReceiver.onReceive调用peekService将返回null 问题,android,android-4.3-jelly-bean,Android,Android 4.3 Jelly Bean,我为安卓4.3编写了一个程序,包含一个主活动、一个广播接收器和一个服务。活动通过其onCreate方法绑定到服务。该活动有一个按钮,用于在未来10秒内安排报警。该警报触发广播接收器.onReceive。此方法尝试保留活页夹,但在某些情况下会失败,peekService返回null 什么有效 单击按钮并等待10秒钟 单击按钮,单击主页,然后在主页屏幕中等待10秒钟 单击按钮,单击活动列表,通过向左滑动关闭活动,重新打开程序并等待10秒(您需要快速:-) 什么不起作用 点击按钮,点击活动列表,向左滑
onCreate
方法绑定到服务。该活动有一个按钮,用于在未来10秒内安排报警。该警报触发广播接收器.onReceive
。此方法尝试保留活页夹,但在某些情况下会失败,peekService
返回null
什么有效
02-05 20:53:29.992: D/ServiceSSCCE.MyService(476): I've been bound.
02-05 20:53:30.179: D/ServiceSSCCE.MainActivity(476): Service connected.
02-05 20:53:43.265: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:53:55.460: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:54:08.531: D/ServiceSSCCE.MyService(764): I've been bound.
02-05 20:54:08.663: D/ServiceSSCCE.MainActivity(764): Service connected.
02-05 20:54:10.890: D/ServiceSSCCE.MyReceiver(764): Awesome, let's get this **** done!
02-05 20:54:23.593: D/ServiceSSCCE.MyReceiver(788): I just received a null binder.
最后一条消息显示测试(4.)失败,而之前的消息显示(1.)、(2.)和(3.)成功
我知道,并回答,以及谷歌在前两页列出的几乎所有相关结果。我尝试了几件事,包括但不限于:
- 从
和主活动调用BroadcastReceiver.onReceive
(尽管我不确定自己是否了解startService
和bindService
的交互方式)startService
- 玩弄意图,尤其是上下文(
VSthis
等等)getApplicationContext
- 将服务设置为前台(请参阅)
简而言之
解决方案包括三件事:
- 使服务成为前台服务
- 在活动中使用startService和绑定启动它。显然,
peek服务
启动服务是不够的;另外,必须有人(一项活动或可能是另一项服务)绑定到它。(对我来说)这是无法理解的
- 在服务声明中添加android:isolatedService=“true”
详细地
MyReceiver.java是正确的
MyService.java中声明的服务确实需要是前台服务:
public class MyService extends Service {
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification.Builder(this)
.setTicker("Bla bla...")
.setContentTitle("Title...")
.setContentText("Text...")
.build();
startForeground(1234, notification);
return super.onStartCommand(intent, flags, startId);
}
...
}
服务中的此更改至少有一次导致我的活动发出连接泄漏警告(尽管我无法重现该行为)。但是,它是通过正确解开连接来固定的;这意味着从onCreate
中删除服务代码,并将相应的onResume
和onStop
方法添加到MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), mConnection, 0);
super.onResume();
}
@Override
protected void onStop() {
unbindService(mConnection);
super.onStop();
}
我们差不多完成了。此时(1),(2.)和(3.)仍然有效,(4.)仍然无效。患者的病情实际上变得更糟:现在BroadcastReceive.onReceive甚至不会被触发
<service
android:name="it.damix.examples.servicesscce.MyService"
android:enabled="true"
android:isolatedProcess="true"></service>
修复所有问题的最后一步是将属性android:isolatedService=“true”
添加到ApplicationManifest.xml中的服务
声明中
<service
android:name="it.damix.examples.servicesscce.MyService"
android:enabled="true"
android:isolatedProcess="true"></service>
+1了解damix911对问题的完整说明以及可能的解决步骤。所有代码的发布使我能够轻松地重新创建测试应用程序 对于案例4为什么失败的问题,简短的回答在于一些未记录的关于孩子行为的细节。在Android框架工程师Dianne Hackborn的一篇文章中,她解释说peekService()要返回一个
IBinder
,某些组件之前必须绑定到该服务,从而导致系统创建一个IBinder
。这篇文章是我找到获得所描述的IBinder的附加条件的唯一地方
这里,对于案例1到案例3,存在MainActivity的实例并已绑定到该服务,创建了一个IBinder
。当接收器运行并调用peek服务()
时,它将获得IBinder
。对于案例4,从最近的任务列表中滑动应用程序会终止整个应用程序流程:活动和绑定服务。当警报随后触发时,将为接收者重新创建应用程序进程,但活动未启动,没有绑定到服务的请求,并且服务未创建,因此peekService()
返回null
我无法复制damix911的解决方案。当我修改服务属性使其作为isolatedProcess
运行时,我得到了一个安全异常(KitKat设备)。我质疑启动该服务并使其成为前台服务将如何改变任何事情。启动它并返回默认(超级)模式确实会导致服务变得粘滞,因此,当刷过之后重新创建进程时,将重新创建服务。但是仍然没有任何绑定到它,因此没有IBinder
供peek服务()
返回
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="it.damix.examples.servicesscce.MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me to schedule an alarm..."
android:onClick="scheduleAlarm"/>
</RelativeLayout>
public class MyService extends Service {
...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification.Builder(this)
.setTicker("Bla bla...")
.setContentTitle("Title...")
.setContentText("Text...")
.build();
startForeground(1234, notification);
return super.onStartCommand(intent, flags, startId);
}
...
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), mConnection, 0);
super.onResume();
}
@Override
protected void onStop() {
unbindService(mConnection);
super.onStop();
}
<service
android:name="it.damix.examples.servicesscce.MyService"
android:enabled="true"
android:isolatedProcess="true"></service>