본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Android/안드로이드] Messenger 를 이용한 IPC.( Service binding )

by 돼지왕 왕돼지 2012. 5. 21.
반응형




 

다른 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. 



반응형

댓글