9

我已阅读有关 Bound Services 的文档,其中显示您可以通过Messages从 Activity 轻松地与远程(即不在同一上下文中)Service 进行通信,但是有什么方法可以将消息从Service发送到绑定活动?例如,我的活动绑定到同一应用程序的正在运行的后台服务,向它发送一条消息,并在收到此消息后,服务回复一条消息给活动。我该如何实现呢?您能否指出一些解释该主题的文档?

4

5 回答 5

29

注意:这仅适用于进程中的服务和活动,而不是远程问题。

使用服务与活动通信涉及创建一个侦听器,您可以将其从活动传递给服务。

您需要制作绑定到活动的服务。

第一步是提供服务。在服务中确保你有一个 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;
}

现在您需要创建某种接口,您可以将其传递给您的服务可以用来向其发送更新的 binder 对象。下面是我的 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);

请记住,即使您绑定到服务,它也不会真正启动,直到您调用启动服务。绑定到服务只是将服务连接到活动。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;
    }
}

希望这可以帮助。

于 2012-08-18T00:37:15.207 回答
7

在Remote Messenger Service Sample的参考文档中找到示例。

于 2012-05-11T09:07:43.590 回答
0

简而言之,答案是将带有 ResponseHandler 的 Messenger 分配给msg.replyTo()。让我们在下面的示例中看看我们是如何做到的。

简要说明此示例的作用: 在此示例中,我们在 MainActivity 中有一个按钮,其 onClick() 链接到 sendMessage(View view)。单击按钮后,我们会向 RemoteService 发送自定义消息。一旦在远程服务中收到自定义消息,我们将 CurrentTime 附加到自定义消息并将其发送回 MainActivity。

MainActivity.java

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();
        }
    }
}

响应处理程序.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();
    }
}

服务连接器.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;
    }
}

远程服务.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;
    }

}

传入处理程序.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;

    }
}
于 2022-02-27T01:53:47.923 回答
0

1) 在自己的 Binder.class 和实现 IInterface.class 对象(匿名或通过直接扩展类)中实现 transact/onTransact 方法,方法是使用传入的 Parcel.class 对象
2) 将本地接口附加到自己的 Binder 对象 3 ) 创建服务并从 onBind 方法返回绑定器代理实现 4) 使用 bindService(ServiceConnection) 创建绑定 5) 这将导致通过在接口实现中创建绑定返回代理绑定器

这是使用内核绑定器空间的 IPC 的 android 实现

简化代码示例:

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 的事务方法相互交谈(4 个使用奇数/前夕代码来恶心本地远程端的示例,因为我们对展位端使用相同的 onTransact 方法)

于 2018-12-24T14:04:02.617 回答
0

应该能够使用 . 像 android billing api 这样的AIDL 文件。它是一种进行 RPC 调用(跨远程进程通信)的方法。但是您必须声明要使用的每种方法。有点像上面已经提到的界面。

于 2019-05-11T06:10:09.753 回答