다른 앱들간 통신하기 위한 여러 방법이 있지만 method 를 직접적으로 호출하고 바로 리턴 받을 수 있는 AIDL 구현 예제 설명
용어
Bind
서비스와 통신하기 위해 연결과정을 binding 이라고 함
bindService() 로 실행된 서비스는 unbindService() 될 때 종료됨
bindService() 로 실행된 서비스는 unbindService() 될 때 종료됨
AIDL (Android Interface Definition Language)
Service 와 client 간 통신 규약 파일이며 service 측과 client 측이 통신하기 위해 동일한 aidl 파일을 공유해야 함
예를 들어 service 와 client 가 다른 프로젝트라면 aidl 을 같은 package 위치에 복사해야 하며 변경 사항 발생시 공유 해야 함
예를 들어 service 와 client 가 다른 프로젝트라면 aidl 을 같은 package 위치에 복사해야 하며 변경 사항 발생시 공유 해야 함
AIDL 예제
Service 와 Client 작성 예제
- https://github.com/bjtj/tjsamples/tree/master/android/RemoteClient
- https://github.com/bjtj/tjsamples/tree/master/android/RemoteServer
1. Service (com.sample.myservice)
com.sample.myservice.IMyService.aidl 작성
// IMyServiceInterface.aidl
package com.sample.myservice;
// Declare any non-default types here with import statements
interface IMyServiceInterface {
String greet();
}
- greet() 함수 제공
com.sample.myservice.MyService.java 작성
package com.sample.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service {
public MyService() {
}
private IMyServiceInterface.Stub binder = new IMyServiceInterface.Stub() {
@Override
public String greet() throws RemoteException {
return "Hello";
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
}
- aidl 파일 작성 후 Android Studio 의 build -> make project 를 해야 aidl 을 자동 인식
- IMyServiceInterface.Stub 을 구현
- onBind() 시 구현한 IMyServiceInterface.Stub 리턴
2. Client 예제 (com.sample.myapp 다른 프로젝트)
IMyService.aidl 복사
- 위에 생성한 aidl 을 복사
com.sample.myapp.MainActivity.java 생성
package com.sample.myapp;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.sample.myservice.IMyServiceInterface;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
private IMyServiceInterface myservice;
private IMyServiceInterface myservice;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myservice = IMyServiceInterface.Stub.asInterface(iBinder);
try {
Log.d(TAG, myservice.greet());
} catch (RemoteException e) {
Log.e(TAG, "exception", e);
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
myservice = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClassName("com.sample.myservice", "com.sample.myservice.MyService");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
unbindService(serviceConnection);
}
}
- 마찬가지로 make project 를 해야 Anroid Studio 가 aidl 파일을 자동 인식
- 외부 service 이기 때문에 intent 에 setClassName() 으로 서비스 지정
- Service 의 package 명과 Service 의 full package 명이 파라메터
- ServiceConnection 의 onServiceConnected() 와 onSerivceDisconnected() 처리
- IMyServiceInterface.Stub.asInterface() 로 따로 casting 필요없음
- aidl 구현 함수들은 RemoteException 을 throw 할 수 있음
- 연결 해제된 경우 등
- onCreate() 에서 bindService() 했으니 onDestroy() 시 unbindService()
Callback 예제
Service -> Client 방향으로 통신할 수 있도록 callback 을 등록
1. Service 수정
com.sample.myservice.IMyCallbackInterface.aidl 생성
// IMyCallbackInterface.aidl
package com.sample.myservice;
// Declare any non-default types here with import statements
interface IMyCallbackInterface {
void onUpdate(int value);
}
- Service 에서 호출할 onUpdate() 함수 제공
com.sample.myservice.IMyServiceInterface 수정
// IMyServiceInterface.aidl
package com.sample.myservice;
// Declare any non-default types here with import statements
import com.sample.myservice.IMyCallbackInterface;
interface IMyServiceInterface {
String greet();
boolean registerCallback(IMyCallbackInterface callback);
boolean unregisterCallback(IMyCallbackInterface callback);
}
- registerCallback(), unregisterCallback() 추가
com.sample.service.MyService.java 수정
package com.sample.myservice;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
private final static String TAG = "MyService";
private RemoteCallbackList<IMyCallbackInterface> callbackList = new RemoteCallbackList<>();
private int value;
public MyService() {
}
private IMyServiceInterface.Stub binder = new IMyServiceInterface.Stub() {
@Override
public String greet() throws RemoteException {
return "Hello";
}
@Override
public boolean registerCallback(IMyCallbackInterface callback) throws RemoteException {
return callbackList.register(callback);
}
@Override
public boolean unregisterCallback(IMyCallbackInterface callback) throws RemoteException {
return callbackList.unregister(callback);
}
};
private final static int MSG_BROADCAST = 0;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_BROADCAST:
{
value++;
int size = callbackList.beginBroadcast();
for (int i = 0; i < size; i++) {
try {
callbackList.getBroadcastItem(i).onUpdate(value);
} catch (RemoteException e) {
Log.e(TAG, "exception", e);
}
}
callbackList.finishBroadcast();
sendEmptyMessageDelayed(MSG_BROADCAST, 1000);
}
break;
default:
break;
}
}
};
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
handler.sendEmptyMessageDelayed(MSG_BROADCAST, 1000);
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}
}
- android.os.RemoteCallbackList 사용
- broadcast
- beginBroadcast() 로 등록된 callback 통신 시작
- 등록된 callback 객수 리턴
- getBroadcastItem() 로 등록된 callback 접근
- finishBroadcast() 로 callback 통신 작업 종료
- register/unregister
2. Client 수정
com.sample.myapp.MainActivity.java 수정
package com.sample.myapp;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.sample.myservice.IMyCallbackInterface;
import com.sample.myservice.IMyServiceInterface;
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
private IMyCallbackInterface.Stub callback = new IMyCallbackInterface.Stub() {
@Override
public void onUpdate(int value) throws RemoteException {
Log.d(TAG, "value: " + value);
}
};
private IMyServiceInterface myservice;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myservice = IMyServiceInterface.Stub.asInterface(iBinder);
try {
Log.d(TAG, myservice.greet());
myservice.registerCallback(callback);
} catch (RemoteException e) {
Log.e(TAG, "exception", e);
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
myservice = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClassName("com.sample.myservice", "com.sample.myservice.MyService");
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
myservice.unregisterCallback(callback);
} catch (RemoteException e) {
Log.e(TAG, "exception", e);
}
unbindService(serviceConnection);
}
}
- IMyCallbackInterface.Stub 구현
- onUpdate() 구현
- onServiceConnected() 에서 callback 등록
- unbindService() 하기 전에 callback 등록 해제
댓글 없음:
댓글 쓰기