【问题标题】:Getting notified when clients attach and detach to an Android Service当客户端附加和分离到 Android 服务时收到通知
【发布时间】:2011-12-16 16:30:47
【问题描述】:

我有一个通过 AIDL 导出 RPC 接口的 Android 服务。该接口是面向连接的,客户端将连接到它,与它进行交易,然后在退出时断开连接。

不幸的是客户端异常退出,例如被系统杀死,它永远没有机会告诉 RPC 接口连接已关闭。这会导致问题。

有什么方法可以让服务在新客户端连接和分离接口时自动获得通知?我找到了onBind()onUnbind(),但它们不是一回事;他们告诉我接​​口是否在使用中。 onUnbind() 仅在最后一个客户端分离时才被调用。

有什么想法吗? (而且服务的设计是由外部需求控制的,无法更改……)

更新:我完全忘了提到我看过linkToDeath(),这几乎完全符合我的要求,但它似乎只能起到相反的作用方式 --- 它允许客户端在服务终止时得到通知。当我尝试它时,似乎什么也没发生。文档有点零散;任何人都知道这是否按我想要的方式工作?如果是这样,如何让它告诉我哪个客户死了?

更新更新:我已经解决了这个问题,但只是作弊。我重新定义了它。我的应用程序实际上主要是使用 NDK 用 C 语言编写的,因此服务的设计很奇怪;因此,我将问题转移到 C 世界并创建了一个小型辅助进程,它使用 Unix 域套接字直接与我的应用程序的本机部分对话。它速度快,非常小,几乎是防弹的——但它仍然在作弊。所以虽然我的问题现在已经解决了,但我仍然想知道实际的答案是什么。

【问题讨论】:

  • 当你说不能改的时候,是不是可以在导出的接口中添加方法,只要不改变已有的方法?或者让服务发送广播,其意图可以通过广播接收器从外部接收?
  • 我可以随心所欲地更改界面,但必须保留整体面向连接的架构。我可以让服务不断发送客户端必须回复的广播,并且假设不回复的客户端已经死亡,但是...... ew。这是你的意思吗? (嘿,如果它会工作,我会试试。)

标签: android android-service android-binder


【解决方案1】:

通过在客户端初始化新的 Binder 对象并通过 AIDL 将其发送到服务来使用 linkToDeath()(但反过来做)。
然后你可以在你的服务里面注册到你客户端的DeathRecipient,当客户端进程异常退出时,框架会通知你。

代码示例 -

在您的.AIDL文件中 - 创建一个将Binder 对象从客户端传递到服务的方法

void registerProcessDeath(in IBinder clientDeathListener);

在客户端 - 初始化一个新对象并通过 AIDL 接口将其传递给您的服务。

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

在服务端 - 获取客户的Binder 并注册到他的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);
    }
};

补充阅读 - 这种机制在框架内非常常见,以防止进程死亡时的内存泄漏 - Alex Lockwood 关于主题 here 的非常好的教程。

【讨论】:

    【解决方案2】:

    也许linkToDeath() 可以在这里提供帮助。

    【讨论】:

    • 我忘了提到 linkToDeath() --- 查看更新。谢谢提醒。
    • 看看这个RemoteCallbackList 我会说你是对的:如果/当 IInterface 的 provider 死亡时,就会宣布死亡。如果您要求您的客户向您的服务注册一些(虚拟)回调,这可能会提供一个解决方案 - 可惜不是一个漂亮的解决方案。一旦客户端死掉,它的(虚拟)回调接口也会死掉,通知你的服务。
    • 啊。这听起来很合理;我会检查一下。 (我的替代计划是强制每个客户端进入自己的进程,将其 pid 通知服务,然后让服务监视器 /proc 查看进程是否消失;所以我对丑陋的数量有一个很高的标准可以容忍避免这样做!)
    猜你喜欢
    • 2014-02-11
    • 2011-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多