我们知道当绑定service时 客户端可以收到服务端异常中断的消息 即onServiceConnected,那么服务器端是否可以监听到client端掉线的消息呢?下面就写个简单的demo用于监听client是否掉线
分三个moudle 分别是client server和AIDL模块 AIDL模块专门放AIDL文件 client server分别依赖AIDL模块
AIDL模块:
IClientCallback
// IClientCallback.aidl
package com.example.commonlib;
// Declare any non-default types here with import statements
interface IClientCallback {
void clientDiedCallBack();
}
IAIDLInterface
// IAIDLInterface.aidl
package com.example.commonlib;
import com.example.commonlib.IClientCallback;
// Declare any non-default types here with import statements
interface IAIDLInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
String getString(String s);
int getInt(int i);
void registerClientCallback(IClientCallback callBack);
}
添加完毕记得rebuild 否则Android studio无法识别这些AIDL
Server端
package com.example.myapplication.server;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Nullable;
import com.example.commonlib.IAIDLInterface;
import com.example.commonlib.IClientCallback;
import java.util.Locale;
/**
* Created by hjcai on 2021/3/29.
*/
public class ServiceInServer extends Service {
RemoteCallbackList<IClientCallback> callbackList;
private static final String TAG = "ServiceInServer";
@Override
public void onCreate() {
super.onCreate();
callbackList = new RemoteCallbackList() {
@Override
public void onCallbackDied(IInterface callback) {
Log.e(TAG, "onCallbackDied: ");
}
};
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
return mBinder;
}
private final IAIDLInterface.Stub mBinder = new IAIDLInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getString(String s) throws RemoteException {
return castClientStringToServer(s);
}
@Override
public int getInt(int i) throws RemoteException {
return 0;
}
@Override
public void registerClientCallback(IClientCallback callBack) throws RemoteException {
Log.e(TAG, "registerClientCallback: ");
callbackList.register(callBack);
}
};
protected String castClientStringToServer(String s) {
Log.e(TAG, "castClientStringToServer: " + s);
return s.toUpperCase(Locale.US);
}
}
别忘了在清单文件注册service
<service android:name="com.example.myapplication.server.ServiceInServer">
<intent-filter>
<action android:name="aaa.aaa" />
</intent-filter>
</service>
Client端
ClientCallBack用于注册到Server端
package com.example.aidlclient;
import android.os.RemoteException;
import com.example.commonlib.IClientCallback;
/**
* Created by hjcai on 2021/3/29.
*/
public class ClientCallBack extends IClientCallback.Stub{
@Override
public void clientDiedCallBack() throws RemoteException {
}
}
ClientServiceConnection
package com.example.aidlclient;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.example.commonlib.IAIDLInterface;
import java.util.List;
/**
* Created by hjcai on 2021/3/29.
*/
class ClientServiceConnection implements ServiceConnection {
private final static ClientServiceConnection INSTANCE = new ClientServiceConnection();
private static final String SERVICE_INTENT = "aaa.aaa";
private static final String TAG = "Client";
IAIDLInterface mServer = null;
private ClientServiceConnection() {
}
public static ClientServiceConnection getInstance() {
return INSTANCE;
}
public void bindService(Context context) {
Log.e(TAG, "bindService: ");
if (null == context) return;
try {
Intent intent = new Intent();
intent.setAction(SERVICE_INTENT);
Intent explicitIntent = getExplicitIntent(intent, context);
context.bindService(explicitIntent, this, Service.BIND_AUTO_CREATE);
} catch (Exception e) {
e.printStackTrace();
}
}
private Intent getExplicitIntent(Intent implicitIntent, Context context) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String className = serviceInfo.serviceInfo.name;
Log.e(TAG, "service package=" + serviceInfo.serviceInfo.packageName);
ComponentName component = new ComponentName(serviceInfo.serviceInfo.packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected: ");
synchronized (this) {
this.mServer = IAIDLInterface.Stub.asInterface(service);
try {
Log.e(TAG, "registerClientCallback: ");
this.mServer.registerClientCallback(new ClientCallBack());
} catch (RemoteException e) {
e.printStackTrace();
}
}
try {
String s = mServer.getString("ACCAaaaa");
Log.e(TAG, "onServiceConnected: " + s);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected: ");
}
@Override
public void onBindingDied(ComponentName name) {
}
@Override
public void onNullBinding(ComponentName name) {
}
}
在界面写个button调用如下方法
public void bind(View view) {
ClientServiceConnection.getInstance().bindService(this);
}
调用顺序
在第三步之后 可以拿到远端服务端的代理 间接调用远端的接口 在第五步之后 如果杀掉client端 会触发服务器端RemoteCallbackList<IClientCallback> callbackList的onCallbackDied 达到监听client端的作用
升级:辨认是哪个client掉线
我们可以通过修改AIDL的接口 来达到这个目的
1.修改接口IAIDLInterface:
void registerClientCallback(IClientCallback callBack,String cookie);//增加一个参数
2.修改client侧注册代码
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected: ");
synchronized (this) {
this.mServer = IAIDLInterface.Stub.asInterface(service);
try {
Log.e(TAG, "registerClientCallback: ");
this.mServer.registerClientCallback(new ClientCallBack(),this.getClass().getName());//关键部分
} catch (RemoteException e) {
e.printStackTrace();
}
}
try {
String s = mServer.getString("ACCAaaaa");
Log.e(TAG, "onServiceConnected: " + s);
} catch (RemoteException e) {
e.printStackTrace();
}
}
3.修改service端的实现
private final IAIDLInterface.Stub mBinder = new IAIDLInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public String getString(String s) throws RemoteException {
return castClientStringToServer(s);
}
@Override
public int getInt(int i) throws RemoteException {
return 0;
}
@Override
public void registerClientCallback(IClientCallback callBack, String cookie) throws RemoteException {
Log.e(TAG, "registerClientCallback: "+cookie);
callbackList.register(callBack,cookie);//主要是这里
}
};
4.修改回调 使用带cookie的回调
callbackList = new RemoteCallbackList<IClientCallback>() {
@Override
public void onCallbackDied(IClientCallback callback, Object cookie) {
super.onCallbackDied(callback, cookie);
// 可以通过cookie判断是哪个client掉线了
Log.e(TAG, "onCallbackDied: "+callback+" cookie "+cookie);
try {
callback.clientDiedCallBack();
} catch (RemoteException e) {
Log.e(TAG, "onCallbackDied: "+e);
e.printStackTrace();
}
}
};