Written by
lsm
on
on
Android App 간 통신
최근 안드로이드 개발 중 서로 다른 어플리케이션끼리 통신할 일이 있었다. 구글에 따르면 AIDL 방식과 Messenger 방식이 있는데, Messenger 방식을 추천하였다. AIDL 방식은 많이 복잡하다 하여 Messenger 방식을 선택하여 개발을 진행하였다.
개발했던 내용을 다음과 같이 정리해본다.
A application - 메시지를 받기 위해 서비스를 띄움, B 앱으로부터 메세지를 받고 답장
B application - A 앱의 서비스와 바인드, 메세지 전송
1. MsgService
- B 앱과 통신할 수 있는 서비스
- B 앱에서 전송한 메세지는 MsgHandler() 클래스 내부의 handleMessage 메소드에서 처리
class MsgService : Service(){
private val handler = MsgHandler()
override fun onBind(intent:Intent) : IBinder{
return Messenger(handler).binder
}
}
2. MsgHandler
- B 앱에서 들어온 메시지를 처리하기 위해 Handler 상속
- B 앱으로 들어온 메시지에 답장하기 위해서는 replyTo로 돌아오는 Messenger 객체에 다시 send 메소드를 호출하면 가능
class MsgHandler : Handler() {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
Logger.d(TAG, "Msg handler ${msg.what}")
when(msg.what){
//TODO : 들어온 메시지 처리
...
//B 앱에 답장
msg.replyTo.send(Message.obtain(null, 1))
}
}
}
3. MsgManager
- A앱의 서비스와 바인드 하기 위한 클래스
- 서비스에 바인드 하기 위해서는 서비스의 패키지 명과 클래스 명을 알 필요가 있음
- ServiceConnection을 통해서 서비스와 연결 유무를 확인할 수 있음
- Intent에 바인드 하고자 하는 서비스를 알림
public class MsgManager{
...
public MsgManager(Context context){
ComponentName cn = new ComponentName("바인드 하는 서비스 패키지", "바인드 하는 서비스 클래스");
Intent intent = new Intent();
intent.setComponent(cn);
}
...
}
- ServiceConnection 정의
public class MsgManager{
private boolean isBound = false;
...
private ServiceConnection conn = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mService = new Messenger(iBinder);
isBound = true;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
isBound = false;
mService = null;
}
};
...
}
- 서비스 bind & unbind
- 일반 Activity context 이용시 Activity가 죽었을 때 같이 죽으면서 unbind가 되지 않아 leak 되는 문제가 발생
- ApplicationContext를 넘겨줌으로써 문제 해결
- 일반 Activity context 이용시 Activity가 죽었을 때 같이 죽으면서 unbind가 되지 않아 leak 되는 문제가 발생
...
public void bindMsgService(){
if(!isBound){
context.bindService(intent, conn, Context.BIND_AUTO_CREATE);
isBound = true;
}
}
...
public void unBindMsgService(){
if(isBound){
context.unbindService(conn);
isBound = false;
}
}
- 메시지 전송
- 메시지의 replyTo에 Messenger를 정의하면 서비스로부터 값을 받을 수 있음
- MsgReplyHandler() 객체는 Handler를 상속
- replyTo에서 넘어오는 메시지 데이터를 처리
Messenger replyMessenger = new Messenger(new MsgReplyHandler());
...
public void sendMsg(int msgType){
if(isBound && mService != null){
Message msg = Message.obtain(null, msgType);
try {
msg.replyTo = replyMessenger; //서비스에서 넘어온 값 처리
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}