詳細的資料還是在官網看吧這個準確:Android 接口定義語言 (AIDL).
雙向通信的話說白了就是在服務端裏面設置回調.然後客戶端註冊回調接口實現雙向.同時系統也提供了RemoteCallbackList這個類方便了我們負責維護遠程接口列表的繁瑣工作,可用於執行從Service到其客戶端的回調 .
定義統一的AIDL
package com.message.client;
// Declare any non-default types here with import statements
interface IRemoteCallBackListener {
void onLoginSuccess(String msg);
void onLoginFail(String msg);
void onLogoutSuccess(String msg);
void onLogoutFail(String msg);
}
//----------------------------------------------------------------------------------------------------------------------------------
//注意在aidl文件裏面引用包
package com.message.client;
import com.message.client.IRemoteCallBackListener;
interface IRemoteService {
void login(String userName , String passWord , String packageName);
void logout(String packageName);
boolean isLogin();
void registerListener(in IRemoteCallBackListener listener); //註冊回調
void unregisterListener(in IRemoteCallBackListener listener); //刪除回調
}
Server端
// manifest需要添加的地方
<service
android:name=".GuideServer">
<intent-filter>
<action android:name="com.message.action.GUIDE"/>
</intent-filter>
</service>
public class GuideServer extends Service{
private RemoteCallbackList<IRemoteCallBackListener> mRemoteCallbackList = new RemoteCallbackList<>();
private IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void login(final String userName, final String passWord, String packageName) throws RemoteException {
new Thread(new Runnable() {
@Override
public void run() {
//模擬延遲任務
try {
Thread.sleep(2000);
if (userName.equals("huluwa") && passWord.equals("123456")) {
loginSuccessCallback("登錄成功: "+userName);
} else {
loginFailCallback("登錄失敗: "+userName);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public void logout(final String packageName) throws RemoteException {
new Thread(new Runnable() {
@Override
public void run() {
//模擬延遲任務
try {
Thread.sleep(2000);
if(packageName.equals("com.message.client")){
logoutSuccessCallback("退出成功!");
}else{
logoutFailCallback("退出失敗!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public boolean isLogin() throws RemoteException {
return false;
}
@Override
public void registerListener(IRemoteCallBackListener listener) throws RemoteException {
LoginClient loginClient = new LoginClient();
if (listener != null) {
mRemoteCallbackList.register(listener);
try {
//
listener.asBinder().linkToDeath(loginClient, 0);
} catch (RemoteException e) {
Log.d("GuideServer", "XXXListener already died.", e);
}
}
}
@Override
public void unregisterListener(IRemoteCallBackListener listener) throws RemoteException {
if (listener != null) {
mRemoteCallbackList.unregister(listener);
}
}
};
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private void loginSuccessCallback(String msg) throws RemoteException{
final int N = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ;i < N; i++){
IRemoteCallBackListener broadcastItem = mRemoteCallbackList.getBroadcastItem(i);
if(broadcastItem != null){
try{
broadcastItem.onLogoutSuccess(msg);
}catch (Exception e){
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
}
private void loginFailCallback(String msg) throws RemoteException{
final int N = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ;i < N; i++){
IRemoteCallBackListener broadcastItem = mRemoteCallbackList.getBroadcastItem(i);
if(broadcastItem != null){
try{
broadcastItem.onLogoutSuccess(msg);
}catch (Exception e){
e.printStackTrace();
}
}
}
mRemoteCallbackList.finishBroadcast();
}
private void logoutSuccessCallback(String msg) throws RemoteException{
final int N = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ;i < N; i++){
IRemoteCallBackListener broadcastItem = mRemoteCallbackList.getBroadcastItem(i);
if(broadcastItem != null){
try{
broadcastItem.onLogoutSuccess(msg);
}catch (Exception e){
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
}
private void logoutFailCallback(String msg) throws RemoteException{
final int N = mRemoteCallbackList.beginBroadcast();
for(int i = 0 ;i < N; i++){
IRemoteCallBackListener broadcastItem = mRemoteCallbackList.getBroadcastItem(i);
if(broadcastItem != null){
try{
broadcastItem.onLogoutFail(msg);
}catch (Exception e){
e.printStackTrace();
}
}
mRemoteCallbackList.finishBroadcast();
}
}
//
private class LoginClient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
Log.d("GuideServer", "BinderDied.");
//todo something
}
}
}
Client端
注意客戶端的AIDL.
public class MainActivity extends AppCompatActivity {
private TextView tv_style;
private EditText et_accotun;
private EditText et_password;
private Button btn_login;
private Button btn_logout;
private IRemoteService iRemoteService;
boolean isConnect;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
iRemoteService = IRemoteService.Stub.asInterface(iBinder);
tv_style.setText("當前狀態:\n連接成功");
isConnect = true;
try {
iRemoteService.registerListener(iRemoteCallBackListener);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
tv_style.setText("當前狀態:\n連接斷開");
isConnect = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_style = findViewById(R.id.tv_style);
et_accotun = findViewById(R.id.et_accotun);
et_password = findViewById(R.id.et_password);
btn_login = findViewById(R.id.btn_login);
btn_logout = findViewById(R.id.btn_logout);
Intent intent = new Intent();
intent.setAction("com.message.action.GUIDE");
intent.setPackage("com.message.server");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(isConnect){
try {
Log.e("TAG","btn_login");
iRemoteService.login(String.valueOf(et_accotun.getText()),String.valueOf(et_password.getText()) , getPackageName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
btn_logout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(isConnect){
try {
iRemoteService.logout(getPackageName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
iRemoteService.unregisterListener(iRemoteCallBackListener);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(serviceConnection);
}
private IRemoteCallBackListener iRemoteCallBackListener = new IRemoteCallBackListener.Stub() {
@Override
public void onLoginSuccess(final String msg) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_style.setText("當前狀態:\n連接成功\n"+msg);
}
});
Toast.makeText(MainActivity.this,"客戶端登錄成功回調====" + msg,Toast.LENGTH_LONG).show();
}
@Override
public void onLoginFail(final String msg) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_style.setText("當前狀態:\n連接成功\n"+msg);
Toast.makeText(MainActivity.this,"客戶端登錄失敗回調====" + msg,Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onLogoutSuccess(final String msg) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_style.setText("當前狀態:\n連接成功\n"+msg);
Toast.makeText(MainActivity.this,"客戶端登出成功回調====" + msg,Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onLogoutFail(final String msg) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_style.setText("當前狀態:\n連接成功\n"+msg);
Toast.makeText(MainActivity.this,"客戶端登出失敗回調====" + msg,Toast.LENGTH_LONG).show();
}
});
}
};
結果如下:
關於監聽客戶端死亡的回調我們使用DeathRecipient這個類就可以了.
參考了這篇文章,做個備份加深理解.