希望你能帮助我,因为我几乎可以肯定它可以做到......但我似乎无法做到。
我正在做一个可能需要很长时间的任务(从几秒钟到几个小时不等),所以我通过一项服务来完成任务和一项活动来启动/停止/监控。有点类似于MP3播放器,这就是为什么我认为这是可能的。
然而,当我旋转屏幕时,活动被破坏/创建(这不是问题),所以这是服务! (这个
1)我要求一些不可能的东西吗?我很难相信它,因为我想要的正是音乐播放器想要的......
2)如果(不可能){还有其他想法吗? }
3)否则{我知道我做错了什么? }
我也会说“你正在做的事情是对的”,因为这会告诉我问题出在代码中,而不是概念中。
这是我的伪代码(android 2.2,api 8):
EDIT1:添加“返回START_NOT_STICKY”,因为它可能很重要......
// THE SERVICE
class MyService extends Service {
private MyInterface.Stub binder = new MyInterface.Stub() {
public int getProgress() {...}
public void doStop() {...}
}
onCreate() {
Log("MyService created");
}
onDestroy() {
Log("MyService destroyed");
doStop();
}
onBind() {
Log("MyService bound");
return binder;
}
onStartCommand() {
(new Thread() {
void run() {
while (!stop) {
//Do long task
}
stopSelf();
}
}).start();
return START_NOT_STICKY;
}
}
// THE ACTIVITY
class MyActivity extends Activity {
MyInterface _service;
ServiceConnection conn = new ServiceConnection() {
onServiceConnected(s) {
_service = MyInterface.Stub.asInterface(s);
}
onServiceDisconnected() {
_service = null;
}
}
onCreate() {
Log("MyActivity created");
bindService(MyService, conn);
}
onDestroy() {
Log("MyActivity destroyed");
unbindService(conn);
}
clickStart() {
startService(new Intent(this, MyService));
}
clickStop() {
_service.doStop();
}
clickProgress() {
_service.getProgress();
}
}
// THE MANIFEST
<application>
<activity name=".MyActivity">
<service name=".MyService" android:process=":remote" />
</application>
Edit2:更多信息。我的伪代码说:
class MyService extends Service {
...
}
然而,这是过于简单化,因为它实际上是:
class MyService extends MyBaseService {
...
}
class MyBaseService extends Service {
...
}
MyBaseService位于不同的包中,甚至位于不同的项目中(“库项目”)。
然后,如果我没有启动/绑定到MyService,而是MyBaseService(并且相应地更改清单),那么一切都按预期工作。
这对我来说已经足够了,因为在MyService中实现的行为(与MyBaseService相关)很容易编码到MyBaseService中,并通过putExtra控制到启动服务的Intent(尽管它打破了OOP,我不介意)
然而,我仍然无法找到为什么这个有效但另一个无效。如果我继续前进,我会报告。
Edit3:修复伪代码(复制onCreate)。但真正的代码没有它。
Edit4:关于程序的通知:
1)一切都按预期开始。
2)用户单击Start,因此运行click_start(),该服务为serviceStart()'ed。
3)用户改变方向。调用MyActivyty.onDestroy(),导致unbindService()。
4)服务被破坏;调用MyService.onDestroy()。
5)重新创建活动。调用MyActivity.onCreate(),导致bindService()。
6)重新创建服务;调用MyService.onCreate()。国家已经失去了。
我的问题是第4步(6只是4的连续性)。
答案 0 :(得分:1)
当然,这并非不可能。正如您所说,音乐应用程序也使用了一项服务,但在旋转手机时不会被杀死。
您遇到的问题如下。您的服务与您的活动绑定。每次屏幕方向改变时,Android都会破坏当前活动并立即重新创建。当涉及到屏幕方向等配置更改时,这是Android的标准行为。显然,你的服务与活动密切相关,所以它也被破坏了。
您有多种方法可以解决此问题。
您可以通过将活动方向设置为固定值来禁止方向更改。 android:screenOrientation="portrait"
您可以通过将android:configChanges="orientation"
属性添加到应用程序清单中的活动来定义您将自己处理此活动的配置更改。执行此操作时,不会销毁重新创建的活动,而是调用方法onConfigurationChanged(Configuration),如果需要,您必须自己处理配置更改。
另一种方法可能是在活动之外的任何地方存储与服务的连接。我认为每次与服务进行通信时都必须使用相同的服务连接。因此,如果您的活动在方向更改后重新创建,那么您还可以创建一个新连接,然后我会获得一项新服务。但我并非100%确定我只知道AsyncTasks的这种行为。
答案 1 :(得分:1)
要点:
基于使用基本服务确实有效的想法(参见Edit2),我从头开始重新编写它(看旧代码,但不是复制粘贴),现在它可以工作了。我的猜测:
1)一般概念是正确的。伪代码是对的。但是我在第一次和第二次写作中做了一些不同的事情。我仍然在寻找差异(也许是以不同的顺序做出的事情,或者是这样;你可以想象真正的代码比这个简化的伪代码要复杂得多)。必须存在差异。为什么我知道它?因为我可以一次又一次地测试新的重写,并且它每次都有效;但是,如果我测试旧的重写(我小心地存储在我的HD中),它每次都会一次又一次地失败。
2)Flo和Nick提出的所有想法都可能是正确的:使用getApplicationContext(),使用远程服务(在不同的过程中)并使用startForeground()将所有这些想法告诉操作系统这项服务很重要所以除非严重缺乏资源,否则不应该被杀死。但是,我想我在第一次写作时犯的错误也使他们的想法失败了。
感谢大家的帮助。如果我能找到差异,我会报告。
答案 2 :(得分:0)
您需要使用startService
代替bindService
(您正在进行的操作)启动它,并使用Service.startForeground
创建持续通知。您可能还需要通知来显示当前正在播放的音频的详细信息。只要此通知存在,它就会使服务保持在前台,因此不是杀人的候选者。