当客户端连接或断开Android服务时如何收到通知

3
我有一个Android服务,通过AIDL导出了一个RPC接口。这个接口是面向连接的,客户端将连接到它,与之交互,然后在退出时断开连接。
不幸的是,如果客户端异常退出,例如被系统杀死,它永远没有机会告诉RPC接口连接已经关闭。这造成了问题。
有没有办法让Service在新客户端附加和分离自己的接口时自动通知呢?我找到了onBind()和onUnbind(),但它们不是同一件事;它们告诉我接口是否正在使用中。只有当最后一个客户端分离时,onUnbind()才会被调用。
有什么想法吗?(服务的设计受外部要求控制,不能更改……)
更新:我完全忘记提到我看过linkToDeath(),它几乎做到了我想要的功能,但它似乎只能反向工作---它允许客户端在服务死亡时得到通知。当我尝试它时,似乎什么也没发生。文档有点不完整;有人确定这是否按照我想要的方式工作吗?如果是,如何让它告诉我哪个客户端死了?
更新更新:我解决了这个问题,但只是通过欺骗来解决的。我重新定义了它。我的应用程序实际上大部分是使用NDK编写的C语言,因此服务的设计有些奇怪;因此,我将问题移至C世界,并创建了一个小型辅助进程,使用Unix域套接字直接与我的应用程序的本地部分通信。它很快,非常小,几乎没有漏洞---但这仍然是欺骗。所以虽然我的问题现在已经解决,但我仍然想知道真正的答案是什么。

当你说它不能被改变时,是否可以添加方法到导出接口中,只要不改变现有的方法即可?或者服务是否可以发送广播,其意图可以通过BroadcastReceiver在外部接收到? - NickT
我可以随意更改界面,但总体的连接导向架构必须保持不变。我可以让服务连续发送广播,客户端必须回复,而假设未回复的客户端已死亡,但是...这样不太好。那就是你的意思吗?(嘿,如果能行,我会尝试。) - David Given
2个回答

5

使用linkToDeath()(但是要反过来)通过在客户端初始化新的Binder对象并通过AIDL发送到服务端来实现。然后,您可以在服务端注册客户端的DeathRecipient并在客户端异常退出时收到框架的通知。

Code Example -

Inside your .AIDL file - Create a method to pass the Binder object from the client to the service

void registerProcessDeath(in IBinder clientDeathListener);

On the client side - Initialize a new object and pass it to your service via AIDL interface.

public void onServiceConnected(ComponentName className, IBinder service) {
    mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
    //Call the registerProcessDeath method from the AIDL file and pass 
    //the new Binder object
    mIMyAidlInterface.registerProcessDeath(new Binder());
}

On the service side - Get the client's Binder and register to his linkToDeath().

private IBinder mBinder; //Instance variable

private final IMyAidlInterface.Stub mStub = new IMyAidlInterface.Stub() {

    @Override
    public void registerProcessDeath(IBinder clientDeathListener) {
        mBinder = clientDeathListener;
        //Create new anonymous class of IBinder.DeathRecipient()
        clientDeathListener.linkToDeath(new IBinder.DeathRecipient() {
               @Override
               public void binderDied() {
               //Do your stuff when process exits abnormally here.
               //Unregister from client death recipient
               mBinder.unlinkToDeath(this,0);
               }
        },0);
    }
};

Additional reading - This mechanisem is very common inside the framework in order to prevent memory leaks on processes deaths - Very good tutorial by Alex Lockwood on the subject here.


2

我忘了提到linkToDeath() --- 请查看更新。感谢提醒。 - David Given
看了一下这个RemoteCallbackList,我想你是对的:如果IInterface的提供者死亡,那么死亡就会被宣布。
如果您需要客户端向您的服务注册一些(虚拟)回调,则这可能提供一个解决方案-不幸的是,这不是一个很好的解决方案。
一旦客户端死亡,它的(虚拟)回调接口也将死亡,通知您的服务。
- JimmyB
啊,那听起来有道理;我会去查一下。(我的备选方案是将每个客户端强制放入自己的进程中,通知服务其 pid,然后让服务监视 /proc,以查看进程是否消失;因此,我对能容忍的丑陋程度有相当高的要求,以避免这样做!) - David Given

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接