绑定客户端断开连接时通知Android服务

Mic*_*rov 10 java service client android bind

我在远程进程中有一个android服务,可以有来自不同客户端的多个绑定.我的问题是,当特定绑定客户端意外断开连接时(即客户端崩溃),如何通知服务?我无法使用onUnbind(),因为只有在所有客户端断开连接后才会调用它.

public class MyService extends Service {

    final Messenger mServiceMessenger = new Messenger(new IncomingHandler());

    @Override
    public IBinder onBind(Intent intent) {
        return mServiceMessenger.getBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_STICKY;
    }

    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
        // Handling messages logic...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Nir*_*uan 6

这可以通过机制来完成Binder.linkToDeath()- 您必须要求每个客户端发送new Binder()他们发起的对象,然后链接到他们(您的客户端)的死亡。我将解释如何使用AIDL文件执行此操作。

(你可以选择任何android IPC机制,只要你可以将Binder对象从你的客户端传递到你的服务)

代码示例 -

.AIDL 在文件内部- 创建一个方法将IBinder对象从客户端传递到服务

void registerProcessDeath(in IBinder clientDeathListener, String packageName);
Run Code Online (Sandbox Code Playgroud)

在客户端- 初始化一个新对象并通过 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 and the client's package name
    mIMyAidlInterface.registerProcessDeath(new Binder(),getPackageName());
}
Run Code Online (Sandbox Code Playgroud)


在服务端——

1. 获取客户的Binder并注册到他的linkToDeath(). 2.使用helper类通过android的IBinder.DeathRecipient类
来处理所有客户端

public class MyService extends Service {
    //Helper class to handle all client's deaths.
    private volatile ClientsDeathWatcher mClientsList;

    @Override
    public IBinder onBind(Intent intent) {
        mClientsList = new ClientsDeathWatcher();
        return mStub;
    }

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

        @Override
        public void registerProcessDeath(IBinder cb, String packageName){

            boolean isRegistered = mClientsList.register(cb , packageName);
        }
    };
}
//This is thread-safe helper class to handle all 
//the client death related tasks.

//All you care abut is the clientDeath() method. 
public class ClientsDeathWatcher {

    private ArrayMap<String, DeathCallBack> mCallbacks = new ArrayMap<>();

    private final class DeathCallBack implements IBinder.DeathRecipient {
        private String pn;
        private IBinder mBinder;

        DeathCallBack(String packageName,IBinder binder) {
            pn = packageName;
            mBinder = binder;
        }

        public void binderDied() {
            synchronized (mCallbacks) {
                mBinder.unlinkToDeath(this,0);
                clientDeath(pn);
            }
        }
    }

    //To be called only from thread-safe functions
    private void clientDeath(String packageName) {
        mCallbacks.remove(packageName);
        //Do your stuff here.
        //$$$$$$$$$
    }

    public boolean register(IBinder token, String packageName) {
        synchronized (mCallbacks) {
            try {
                if (!mCallbacks.containsKey(packageName)) {
                    DeathCallBack mDeathCallBack = new DeathCallBack(packageName,token);
                    mCallbacks.put(packageName, mDeathCallBack);
                    //This is where the magic happens
                    token.linkToDeath(mDeathCallBack, 0);
                }
                return true;
            } catch (RemoteException e) {
                e.printStackTrace();
                return false;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


djo*_*djo 1

您可以使用您拥有的 IncomingHandler 处理程序,并从客户端发送一条消息,表明在调用 unbindService(serviceConnection) 之前它将被解除绑定,保留信使(客户端)的数组列表,并在收到消息时添加/删除。

您还可以尝试发送虚拟消息,如果收到 RemoteException 则意味着远程客户端已死亡。

检查这个例子http://developer.android.com/reference/android/app/Service.html

提炼:

class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_REGISTER_CLIENT:
                mClients.add(msg.replyTo);
                break;
            case MSG_UNREGISTER_CLIENT:
                mClients.remove(msg.replyTo);
                break;
            case MSG_SET_VALUE:
                mValue = msg.arg1;
                for (int i=mClients.size()-1; i>=0; i--) {
                    try {
                        mClients.get(i).send(Message.obtain(null,
                                MSG_SET_VALUE, mValue, 0));
                    } catch (RemoteException e) {
                        // The client is dead.  Remove it from the list;
                        // we are going through the list from back to front
                        // so this is safe to do inside the loop.
                        mClients.remove(i);
                    }
                }
                break;
            default:
                super.handleMessage(msg);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 基于两个答案的类似方法:每个“消息”都包含您需要回复的“Messenger”。每个`Messanger`都包含客户端的`IBinder`来进行底层通信。我想这可以大致像“msg.replyTo.getBinder().linkToDeath()”一样使用来获取有关客户端死亡的通知。注意:死亡!=绑定状态(也许)。 (2认同)