我有一个录音应用程序,我正在为此开发一个小部件。
录制是由处于前台状态的服务中运行的音频引擎执行的。
每当音频引擎状态变为暂停/播放/录制时,广播就会被发送,并由更新小部件的接收者处理。
因此,单击窗口小部件中的记录按钮开始记录,这将导致广播被发送,最后记录按钮在窗口小部件中变为红色。如果您从应用程序而不是小部件开始录制,也会发生同样的事情。
到目前为止一切都很好。
现在,如果服务因某种原因被杀死,则不会调用onDestroy()并且我没有机会发送暂停或关闭广播,以便关闭记录按钮。结果:按钮保持红色,而录制已停止。
这是可能发生的最糟糕的事情。
为什么呢?用户查看他的主屏幕,他/她看到红色按钮并认为仍在执行录制。
与音乐播放不同,用户可以注意到音乐何时停止通过耳机播放...录音时,如果音乐停止,则不会听到任何声音。
我可以理解系统需要杀死服务。我很好。我不需要重新启动服务以及所有这些。
但是如果服务关闭,我需要更新小部件,这样用户就不会被误导,认为他的采访/音乐会/排练/备忘录仍然被记录,而事实并非如此。
那么如果服务被杀,我如何快速更新小部件 ?
答案 0 :(得分:3)
我发现我认为是对自己问题的回答。
我在我的服务中从onStartCommand
()返回START_STICKY。
如果我从DDMS手动终止服务,我会在logcat中得到它:
I/ActivityManager( 2500): Process com.foo.bar (pid 21874) has died.
W/ActivityManager( 2500): Scheduling restart of crashed service com.foo.bar/.FooBarService in 5000ms
几秒钟后:
I/ActivityManager( 2500): Start proc com.foo.bar for service com.foo.bar/.FooBarService: pid=22036 uid=10107 gids={1015, 3003}
该服务确实重启,这允许我从onStartCommand()
发送广播以指示音频引擎已暂停(我不会自动恢复录制)。
窗口小部件提供程序对此广播作出反应并适当地更新窗口小部件。
这适用于Froyo并解决了我的问题:用户在查看窗口小部件时不会被误导。由于引擎崩溃,录制停止,小部件反映了这一点。
它不是防弹的,因为它依赖于系统自动重启服务,但我认为这是非常安全的。
答案 1 :(得分:0)
那么如果服务被杀,我怎么能快速更新小部件呢?
你做不到。因此,使用startForeground()
向Android表明您的服务是前台用户体验的一部分。
答案 2 :(得分:0)
当用户在最近的任务列表中滑动它时,前台服务的进程将被终止。
在轻扫时刻,机器人会调用(*)您服务的onTaskRemoved方法。您可以在那里更新您的小部件:
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.i(TAG, "onTaskRemoved, stopping service");
AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
ComponentName widgetComponentName = new ComponentName(this, MyWidgetProvider.class);
widgetManager.updateAppWidget(widgetComponentName, buildWidgetRemoteViews());
stopSelf();
}
如果您在stopSelf
内拨打onTaskRemoved
,服务将正常结束:onDestroy
将被调用,并且不会安排重启。
如果您不致电stopSelf
,则Android将终止进程并继续执行常规服务终止 - 根据onStartCommand
返回值:
START_NOT_STICKY
- 服务不会重新启动START_STICKY
- 服务将以空意图重新启动让我强调一下 - 即使你不打电话给stopSelf
,服务也会在onTaskRemoved
退出时停止运作。因此,您无法在Handler上发送广播或安排某些内容。但是,如果您真的想要广播,请使用AlarmManager:
final int requestCode = 101;
final AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
final PendingIntent clearWidget = PendingIntent.getBroadcast(
this,
requestCode,
getClearWidgetIntent(),
PendingIntent.FLAG_UPDATE_CURRENT);
// if broadcast arrives while process is shutting down, widget update may fail
// 100ms was always OK on devices I've tested and instantaneous for user
final long startDelay = 100;
alarmManager.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + startDelay,
clearWidget);
我遇到了和你一样的问题,并且最初以同样的方式解决了它 - onStartCommand
中已清除的小部件。但是在其中一个设备上,服务的重启始终在5秒内完成,这对用户来说非常明显,让人觉得应用程序很慢。
注意:
*)实际上它可能没有被调用 - 参见docs