我已阅读关于绑定服务的文档,其中显示你可以通过消息从一个Activity轻松地与远程(即不在同一上下文中)的服务进行通信。但是,是否有任何方法可以从服务发送消息到绑定的Activity?例如,我的Activity绑定到同一应用程序的正在运行的后台服务,将消息发送给它,接收到这个消息后服务回复给Activity一个消息.. 我该如何实现这个功能?你能指向一些解释这个主题的文档吗?
我已阅读关于绑定服务的文档,其中显示你可以通过消息从一个Activity轻松地与远程(即不在同一上下文中)的服务进行通信。但是,是否有任何方法可以从服务发送消息到绑定的Activity?例如,我的Activity绑定到同一应用程序的正在运行的后台服务,将消息发送给它,接收到这个消息后服务回复给Activity一个消息.. 我该如何实现这个功能?你能指向一些解释这个主题的文档吗?
注意:此方法仅适用于进程内服务和活动,不适用于远程服务。
使用服务与活动进行通信需要创建一个监听器,并将其从活动传递到服务中。
您需要创建一个绑定到活动的服务。
第一步是创建一个服务。在服务中确保您有一个Binder对象和返回Binder对象的方法。以下是我在我的服务中使用的示例,以检索我的Binder。还请注意,该Binder具有设置监听器的方法,它将保存为BoundServiceListener类型字段。
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class DownloadBgBinder extends Binder {
public DownloadBgService getService() {
// Return this instance of LocalService so clients can call public methods
return DownloadBgService.this;
}
public void setListener(BoundServiceListener listener) {
mListener = listener;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
现在,您需要创建某种接口,可以将其传递给绑定器对象,以便您的服务可以使用它来发送更新。以下是我的BoundServiceListener。
public interface BoundServiceListener {
public void sendProgress(double progress);
public void finishedDownloading();
}
现在,在你的活动中,你需要创建一个ServiceConnection对象,用于绑定到服务。所以添加一些类似这样的内容。
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
DownloadBgBinder binder = (DownloadBgBinder) service;
mService = binder.getService();
binder.setListener(new BoundServiceListener() {
@Override
public void sendProgress(double progress) {
// Use this method to update our download progress
}
@Override
public void finishedDownloading() {
}
});
mBound = true;
}
binder.setListener(new BoundServiceListener() {
@Override
public void sendProgress(double progress) {
// Use this method to update our download progress
}
@Override
public void finishedDownloading() {
}
});
这部分是我实际发送BoundServiceListener接口到服务类的地方。然后服务类在这里使用该监听器对象。
if (mListener!=null)
mListener.finishedDownloading();
if (mListener!=null)
mListener.sendProgress(percent);
Intent intent = new Intent(this, DownloadBgService.class);
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
请注意,即使您绑定到服务,直到调用start service,它实际上并未启动。绑定服务只是将服务连接到活动中。startService()方法调用服务。
onStartCommand(Intent intent, int flags, int startId)
<service android:name=".services.DownloadBgService" />
同时,在活动离开时解除服务绑定:
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
public class MainActivity extends AppCompatActivity {
ServiceConnector serviceConnector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.serviceConnector = new ServiceConnector();
Intent intent = new Intent(this,RemoteService.class);
bindService(intent,serviceConnector, Context.BIND_AUTO_CREATE);
}
public void sendMessage(View view) {
Message msg = Message.obtain();
msg.replyTo = new Messenger(new ResponseHandler(this));
Bundle bundle = new Bundle();
bundle.putString("MyString", "Time");
msg.setData(bundle);
try {
this.serviceConnector.getMessenger().send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
ResponseHandler.java
public class ResponseHandler extends Handler {
MainActivity mainActivity;
public ResponseHandler(Context context){
this.mainActivity = (MainActivity) context;
}
@Override
public void handleMessage(@NonNull Message msg) {
Bundle data = msg.getData();
String dataString = data.getString("respData");
Toast.makeText(this.mainActivity,dataString,Toast.LENGTH_SHORT).show();
}
}
ServiceConnector.java
public class ServiceConnector implements ServiceConnection {
private Messenger messenger;
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder)
{
this.messenger = new Messenger(iBinder);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
this.messenger = null;
}
public Messenger getMessenger(){
return this.messenger;
}
}
RemoteService.java
public class RemoteService extends Service {
private final IBinder iBinder = new Messenger(new IncomingHandler(this)).getBinder();
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return iBinder;
}
}
IncomingHandler.java
public class IncomingHandler extends Handler {
private RemoteService remoteService;
public IncomingHandler(Context context)
{
this.remoteService = (RemoteService)context;
}
public RemoteService getService()
{
return this.remoteService;
}
@Override
public void handleMessage(@NonNull Message msg) {
try {
msg.replyTo.send(getCurrentTime(msg));
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Message getCurrentTime(Message msg){
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss MM/dd/yyyy", Locale.US);
Message resp = Message.obtain();
Bundle bResp = new Bundle();
bResp.putString("respData", msg.getData().getString("MyString") + " : " +(dateFormat.format(new Date())).toString());
resp.setData(bResp);
return resp;
}
}
1) 在自己的Binder.class和binder代理实现IInterface.class对象中实现transact/onTransact方法(通过直接扩展类或匿名方式),并使用传递给这些方法的Parcel.class对象
2) 将本地接口附加到自己的Binder对象上
3) 创建服务并从onBind方法返回一个binder代理实现
4) 与bindService(ServiceConnection)建立绑定
5) 这将通过创建的接口实现返回代理binder
这是在Android中使用内核binder空间实现IPC的方法。
代码示例:
class ServiceIPC extends Service {
@Override
public Binder onBind() {
return new IInterface() {
IInterface _local = this;
@Override
public IBinder asBinder() {
return new Binder()
{
//
// allow distinguish local/remote impl
// avoid overhead by ipc call
// see Binder.queryLocalInterface("descriptor");
//
attachLocalInterface(_local,"descriptor");
}
@Override
public boolean onTransact(int code,
Parcel in,
Parcel out,
int flags)
throws RemoteException {
//
// your talk between client & service goes here
//
return whatsoever // se super.onTransact();
}
}
}
}.asBinder();
}
}
然后,您可以在客户端和服务端使用IBinder的transact方法相互通信(例如,使用奇偶代码表示本地远程方面,因为我们在双方都使用相同的onTransact方法)。