我正在编写我的第一个Android应用程序,试图弄清楚服务和活动之间的通信。我有一个服务,将在后台运行,并做一些gps和基于时间的日志记录。我将有一个活动,将用于启动和停止服务。
因此,首先,我需要能够确定当活动启动时服务是否正在运行。这里还有一些其他的问题,所以我想我可以解决(但请随意提供建议)。
My real problem: if the Activity is running and the Service is started, I need a way for the Service to send messages to the Activity. Simple Strings and integers at this point - status messages mostly. The messages will not happen regularly, so I don't think polling the service is a good way to go if there is another way. I only want this communication when the Activity has been started by the user - I don't want to start the Activity from the Service. In other words, if you start the Activity and the Service is running, you will see some status messages in the Activity UI when something interesting happens. If you don't start the Activity, you will not see these messages (they're not that interesting).
似乎我应该能够确定服务是否正在运行,如果是的话,将活动添加为侦听器。然后在Activity暂停或停止时删除Activity作为监听器。这真的可能吗?我能想出的唯一方法是让活动实现Parcelable并构建一个AIDL文件,这样我就可以通过服务的远程接口传递它。这似乎是多余的,但我不知道活动应该如何实现writeToParcel() / readFromParcel()。
有没有更简单或更好的方法?谢谢你的帮助。
编辑:
对于稍后对此感兴趣的人来说,在示例目录:/apis/app/RemoteService.java中有来自谷歌的通过AIDL处理此问题的示例代码
与服务通信有三种明显的方式:
使用意图
使用AIDL
使用服务对象本身(作为单例)
在你的情况下,我选择第三种。对它自己的服务做一个静态引用,并在onCreate()中填充它:
void onCreate(Intent i) {
sInstance = this;
}
创建一个静态函数MyService getInstance(),该函数返回静态sInstance。
Then in Activity.onCreate() you start the service, asynchronously wait until the service is actually started (you could have your service notify your app it's ready by sending an intent to the activity.) and get its instance. When you have the instance, register your service listener object to you service and you are set. NOTE: when editing Views inside the Activity you should modify them in the UI thread, the service will probably run its own Thread, so you need to call Activity.runOnUiThread().
您需要做的最后一件事是删除activity . onpause()中对侦听器对象的引用,否则您的活动上下文实例将泄漏,这不好。
注意:此方法仅在应用程序/活动/任务是唯一访问服务的进程时有用。如果不是这种情况,你必须使用选项1。或2。
与服务通信有三种明显的方式:
使用意图
使用AIDL
使用服务对象本身(作为单例)
在你的情况下,我选择第三种。对它自己的服务做一个静态引用,并在onCreate()中填充它:
void onCreate(Intent i) {
sInstance = this;
}
创建一个静态函数MyService getInstance(),该函数返回静态sInstance。
Then in Activity.onCreate() you start the service, asynchronously wait until the service is actually started (you could have your service notify your app it's ready by sending an intent to the activity.) and get its instance. When you have the instance, register your service listener object to you service and you are set. NOTE: when editing Views inside the Activity you should modify them in the UI thread, the service will probably run its own Thread, so you need to call Activity.runOnUiThread().
您需要做的最后一件事是删除activity . onpause()中对侦听器对象的引用,否则您的活动上下文实例将泄漏,这不好。
注意:此方法仅在应用程序/活动/任务是唯一访问服务的进程时有用。如果不是这种情况,你必须使用选项1。或2。
使用信使是在服务和活动之间进行通信的另一种简单方法。
在Activity中,创建带有相应Messenger的Handler。这将处理来自服务的消息。
class ResponseHandler extends Handler {
@Override public void handleMessage(Message message) {
Toast.makeText(this, "message from service",
Toast.LENGTH_SHORT).show();
}
}
Messenger messenger = new Messenger(new ResponseHandler());
Messenger可以通过将其附加到Message来传递给服务:
Message message = Message.obtain(null, MyService.ADD_RESPONSE_HANDLER);
message.replyTo = messenger;
try {
myService.send(message);
catch (RemoteException e) {
e.printStackTrace();
}
在API演示中可以找到完整的示例:MessengerService和MessengerServiceActivity。关于MyService如何工作,请参阅完整的示例。
绑定是另一种通信方式
创建回调
public interface MyCallBack{
public void getResult(String result);
}
活动方面:
Implement the interface in the Activity
Provide the implementation for the method
Bind the Activity to Service
Register and Unregister Callback when the Service gets bound and unbound with
Activity.
public class YourActivity extends AppCompatActivity implements MyCallBack{
private Intent notifyMeIntent;
private GPSService gpsService;
private boolean bound = false;
@Override
public void onCreate(Bundle sis){
// activity code ...
startGPSService();
}
@Override
public void getResult(String result){
// show in textView textView.setText(result);
}
@Override
protected void onStart()
{
super.onStart();
bindService();
}
@Override
protected void onStop() {
super.onStop();
unbindService();
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
GPSService.GPSBinder binder = (GPSService.GPSBinder) service;
gpsService= binder.getService();
bound = true;
gpsService.registerCallBack(YourActivity.this); // register
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
bound = false;
}
};
private void bindService() {
bindService(notifyMeIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void unbindService(){
if (bound) {
gpsService.registerCallBack(null); // unregister
unbindService(serviceConnection);
bound = false;
}
}
// Call this method somewhere to start Your GPSService
private void startGPSService(){
notifyMeIntent = new Intent(this, GPSService.class);
startService(myIntent );
}
}
服务端:
Initialize callback
Invoke the callback method whenever needed
public class GPSService extends Service{
private MyCallBack myCallback;
private IBinder serviceBinder = new GPSBinder();
public void registerCallBack(MyCallBack myCallback){
this.myCallback= myCallback;
}
public class GPSBinder extends Binder{
public GPSService getService(){
return GPSService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent){
return serviceBinder;
}
}