다른 process 에서 돌고 있는 service와 통신할 때는 Messenger를 이용하는 방법이 있다.
Activity SIde
먼저 Activity에서의 bindService 방법까지는 AIDL 과 같다.
단, ServiceConection class의 onServiceConnected 내용이 바뀌게 된다.
왜냐? 전달되어오는 IBinder 가 Messenser.getBinder() 를 통해 얻어진 객체이기 때문이다.
따라서 Messenser mService = new Messenger( service ); 로 service를 받아와야 한다.
Messege를 보낼 때는, Messenger.send( Message ) 를 이용하며, 돌아오는 messege 를 handling 해줄 다른 Messenger 를 링크해주면 된다. 뭘로? Message.replyTo 에다 설정해줘서..
(무슨 말인지 감이 안 올꺼다. 아래를 실제 코드를 보면서 다시 한번 읽어보면 이해가 갈꺼다. )
public class ServiceTestActivityWithMessenger extends Activity{
private Messenger mService;
private final Messenger mMessenger = new Messenger( new IncomingHandler() );
private static final String TAG = "ServiceTestActivityWithMessenger";
private static final int MSG_REGISTER_CLIENT = 44;
private static final int MSG_SET_VALUE = 56;
private static final int MSG_UNREGISTER_CLIENT = 77;
private static boolean mIsBound = false;
class IncomingHandler extends Handler{
@Override
public void handleMessage( Message msg ){
switch ( msg.what ){
case ServiceTestWithMessenger.MSG_SET_VALUE:
Log.d( TAG, msg.arg1 + "" );
break;
default:
super.handleMessage( msg );
}
}
}
ServiceConnection conn = new ServiceConnection(){
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d( TAG, "onServiceDisconnected()");
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger( service );
Log.d( TAG, "onServiceConnected()");
try{
Message msg = Message.obtain( null, MSG_REGISTER_CLIENT );
msg.replyTo = mMessenger;
mService.send( msg );
msg = Message.obtain( null, MSG_SET_VALUE, this.hashCode(), 0 );
mService.send( msg );
}
catch( RemoteException e ){ }
}
};
@Override
public void onCreate( Bundle bun ){
super.onCreate( bun );
LinearLayout ll = new LinearLayout( getBaseContext() );
ll.setLayoutParams( new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT ) );
ll.setOrientation( LinearLayout.VERTICAL );
Button btn3 = new Button( getBaseContext() );
btn3.setOnClickListener(new Button.OnClickListener(){
public void onClick( View v ){
Intent i = new Intent( "com.digitalaria.test.servicetestwithmessenger");
bindService( i, conn, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
});
btn3.setText( "Bind_Service" );
Button btn4 = new Button( getBaseContext() );
btn4.setOnClickListener(new Button.OnClickListener(){
public void onClick( View v ){
if ( mIsBound ){
try{
Message msg = Message.obtain( null, MSG_UNREGISTER_CLIENT );
msg.replyTo = mMessenger;
mService.send( msg );
}
catch( RemoteException e ){ }
unbindService( conn );
mIsBound = false;
}
}
});
btn4.setText( "Unbind_Service" );
LayoutParams param = new LayoutParams( LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT );
ll.addView(btn3, param);
ll.addView(btn4, param);
setContentView( ll );
}
public void onDestroy(){
super.onDestroy();
if ( mIsBound ){
unbindService( conn );
mIsBound = false;
}
}
}
Service Side
앞선 Activity 쪽도 Server side의 이해 없이 100% 이해는 좀 어려울 꺼라 본다.
그래도 Activity 쪽을 거의 다 이해했다면 수월하다. ( Service 파트를 살짝 설명해 놨으니 )
기존과 같이 onBind 에서 IBinder 객체를 retern 하는 것은 같다. 다른 점은 해당 service가 아닌,
Messenger.getBinder() 를 통해 IBinder를 return 해준다는 것이다.
Service쪽은 매우 간단하다. 위의 Messenger에 바로 handler를 지정해서 처리하면 되고,
직접 통신하는 것은 Activity 쪽에서 지정한 replyTo 쪽으로 메세지를 보내주면 된다.
더 쉬운 이해를 위해 코드를 첨부한다.
public class ServiceTestWithMessenger extends Service{
private static final String TAG = "ServiceTestWithMessenger";
ArrayList<Messenger> mClients = new ArrayList<Messenger>();
static final int MSG_REGISTER_CLIENT = 44;
static final int MSG_UNREGISTER_CLIENT = 56;
static final int MSG_SET_VALUE = 77;
int mValue = 0;
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){
mClients.remove( i );
}
}
break;
default:
super.handleMessage( msg );
}
}
}
final Messenger mMessenger = new Messenger( new IncomingHandler());
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy(){
super.onDestroy();
}
@Override
public IBinder onBind(Intent arg0) {
return mMessenger.getBinder();
}
}
Summary
기존 service binding은 이해했다고 보고, Activity 에서 추가로 필요한 것은 2개의 Messenger.
하나는 Service에게 message 를 보낼 녀석. 하나는 Service쪽 Messenger에서 보내는 message 를 받을 Messenger. ( 이녀석은 replyTo 로 설정해서 보냈지? )
Server에서 추가로 필요한 것은 Activity에 message 를 전달할 messenger 객체를 유지 + 전달되어온 message 처리할 Messenger 정의.
추가되는 요구사항은 onBind 에서 Messenger.getBinder() 를 return.
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[Android/안드로이드] Bound Services 고급정보, (0) | 2012.05.21 |
---|---|
[Android/안드로이드] Service 고급정보. (0) | 2012.05.21 |
[Android/안드로이드] Task & Back Stack. (0) | 2012.05.21 |
[Android/안드로이드] Loader ( HoneyComb 부터 도입된 api. ) (2) | 2012.05.18 |
[Android/안드로이드] Fragment 에 대하여. (7) | 2012.05.18 |
댓글