Akashic Records

Android Inter-App Communication 본문

오래된글/Articles

Android Inter-App Communication

Andrew's Akashic Records 2018. 4. 19. 15:04
728x90

이번 튜토리얼에서는 두 개의 Process 사이에서  하나가 다른 Process의 Service을 호출하는 방법에 대하여 설명하고 있습니다.


본 문서에서는 다음 내용을 다룹니다.

  • Invocation Handler을 작성하는 방법

  • Remote Service을 Bind 하는 방법

  • Invocation을 호출한 Process에게 Value Return 하는 방법


Step 1: Create the Service

Invocation될 Service을 만듭니다. Service에는반드시 IBinder 객체를 Return하는 onBind Method을 Override해야 합니다.

Service에서는 Messenger 컴포넌트를 사용합니다. 이 Messenger 컴포넌트는 내부 Process 간 Communication 이 가능하게 해줍니다.

public class RemoteService extends Service

{

private Messenger messenger; //receives remote invocations

@Override

public IBinder onBind(Intent intent)

{

if(this.messenger == null)

{

synchronized(RemoteService.class)

{

if(this.messenger == null)

{

this.messenger = new Messenger(new IncomingHandler());

}

}

}

//Return the proper IBinder instance

return this.messenger.getBinder();

}


Step 2: Implement the Handler

Handler는 Messenger을 등록할수 있는 컴포넌트 입니다. 이 컴포넌트는 Remote Invocation을 받을 수 있는 컴포너트 중 하나 입니다.

Handler는 들어온 요청의 Messenger에 따라 요청을 처리하고 응답을 보내게 되어있습니다.

private class IncomingHandler extends Handler

{

@Override

               public void handleMessage(Message msg)

{

System.out.println("*****************************************");

System.out.println("Remote Service successfully invoked!!!!!!");

System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(RemoteService.this.getApplicationContext(), "Remote Service invoked-("+what+")", Toast.LENGTH_LONG).show();

//Setup the reply message

Message message = Message.obtain(null, 2, 0, 0);

try

{

//make the RPC invocation

Messenger replyTo = msg.replyTo;

replyTo.send(message);

}

catch(RemoteException rme)

{

//Show an Error Message

Toast.makeText(RemoteService.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();

}

   }

}


아래는 RemoterService Application의 Full Source입니다.


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

     package="org.openmobster.remote.service.android.app"

     android:versionCode="1"

     android:versionName="1.0">

   <application android:label="@string/app_name" android:icon="@drawable/icon">

       <activity android:name="org.openmobster.app.MainActivity"

                 android:label="@string/app_name">

           <intent-filter>

               <action android:name="android.intent.action.MAIN" />

               <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

           <intent-filter>

               <action android:name="android.intent.action.VIEW" />

           </intent-filter>

       </activity>

       

       <service android:name="org.openmobster.app.RemoteService" android:exported="true">

       </service>

   </application>

   <uses-permission android:name="android.permission.INTERNET" />

</manifest>

“org.openmobster.app.MainActivity”는 Hello world 수준으로 만들어 줍니다.


RemoteService

package org.openmobster.app;


import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.Handler;

import android.os.Message;

import android.os.Messenger;

import android.os.RemoteException;

import android.widget.Toast;


public class RemoteService extends Service

{

private Messenger messenger; //receives remote invocations

@Override

public IBinder onBind(Intent intent)

{

if(this.messenger == null)

{

synchronized(RemoteService.class)

{

if(this.messenger == null)

{

this.messenger = new Messenger(new IncomingHandler());

}

}

}

//Return the proper IBinder instance

return this.messenger.getBinder();

}

private class IncomingHandler extends Handler

{

@Override

       public void handleMessage(Message msg)

{

System.out.println("*****************************************");

System.out.println("Remote Service successfully invoked!!!!!!");

System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(RemoteService.this.getApplicationContext(), "Remote Service invoked-("+what+")", Toast.LENGTH_LONG).show();

//Setup the reply message

Message message = Message.obtain(null, 2, 0, 0);

try

{

//make the RPC invocation

Messenger replyTo = msg.replyTo;

replyTo.send(message);

}

catch(RemoteException rme)

{

//Show an Error Message

Toast.makeText(RemoteService.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();

}

       }

}

}


Step 3: Create a Client ServiceConnection Object

Client가 Service에 바인딩하는 경우 이 호출은 비동기 방식입니다. 시스템은 클라이언트에게 ServiceConnection 같은 Callback 메커니즘을 제공하고 있습니다.

클라이언트는 제공된 IBinder 인스턴스를 사용하여 Messenger 객체를 설정합니다.

private class RemoteServiceConnection implements ServiceConnection

{

@Override

public void onServiceConnected(ComponentName component, IBinder binder)

{

MainActivity.this.messenger = new Messenger(binder);

MainActivity.this.isBound = true;

}


@Override

public void onServiceDisconnected(ComponentName component)

{

MainActivity.this.messenger = null;

MainActivity.this.isBound = false;

}

}


Step 4: Bind to the Remote Service

Intent을 생성하고 Invoke될 Service을 가리키는 ClassName을 지정합니다.

@Override

protected void onStart()

{

super.onStart();

//Bind to the remote service

Intent intent = new Intent();

intent.setClassName("org.openmobster.remote.service.android.app", "org.openmobster.app.RemoteService");

this.bindService(intent, this.connection, Context.BIND_AUTO_CREATE);

}


Step 5: Make the Remote Invocation

Message.obtain을 이용하여 Message 객체를 생성합니다. message.replyTo에 Local Messenger를 담습니다. Messenger에 Message을 담아 Send합니다.

//Setup the message for invocation

Message message = Message.obtain(null, 1, 0, 0);

try

{

//Set the ReplyTo Messenger for processing the invocation response

message.replyTo = MainActivity.this.replyTo;

//Make the invocation

MainActivity.this.messenger.send(message);

}

catch(RemoteException rme)

{

//Show an Error Message

Toast.makeText(MainActivity.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();

}


아래는 RemoteClient Full Source입니다.


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

     package="org.openmobster.app"

     android:versionCode="1"

     android:versionName="1.0">

   <application android:label="@string/app_name" android:icon="@drawable/icon">

       <activity android:name=".MainActivity"

                 android:label="@string/app_name">

           <intent-filter>

               <action android:name="android.intent.action.MAIN" />

               <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

           <intent-filter>

               <action android:name="android.intent.action.VIEW" />

           </intent-filter>

       </activity>

   </application>

   <uses-permission android:name="android.permission.INTERNET" />

</manifest>


/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical" android:layout_width="fill_parent"

android:layout_height="fill_parent">

<Button android:id="@+id/invoke"

           android:layout_width="wrap_content"

           android:layout_height="wrap_content"

           android:text="Invoke Remote Service" />                                                                           

</LinearLayout>


MainActivity

package org.openmobster.app;


import java.lang.reflect.Field;


import android.app.Activity;

import android.content.ComponentName;

import android.content.Context;

import android.content.Intent;

import android.content.ServiceConnection;

import android.os.Bundle;

import android.os.Handler;

import android.os.IBinder;

import android.os.Message;

import android.os.Messenger;

import android.os.RemoteException;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;


public class MainActivity extends Activity

{

private Messenger messenger = null; //used to make an RPC invocation

private boolean isBound = false;

private ServiceConnection connection;//receives callbacks from bind and unbind invocations

private Messenger replyTo = null; //invocation replies are processed by this Messenger

public MainActivity()

{

}

@Override

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

this.connection = new RemoteServiceConnection();

this.replyTo = new Messenger(new IncomingHandler());

}

@Override

protected void onStart()

{

super.onStart();

//Bind to the remote service

Intent intent = new Intent();

intent.setClassName("org.openmobster.remote.service.android.app", "org.openmobster.app.RemoteService");

this.bindService(intent, this.connection, Context.BIND_AUTO_CREATE);

}

@Override

protected void onStop()

{

super.onStop();

//Unbind if it is bound to the service

if(this.isBound)

{

this.unbindService(connection);

this.isBound = false;

}

}


@Override

protected void onResume()

{

try

{

super.onResume();

//render the main screen

String layoutClass = this.getPackageName()+".R$layout";

String main = "main";

Class clazz = Class.forName(layoutClass);

Field field = clazz.getField(main);

int screenId = field.getInt(clazz);

this.setContentView(screenId);

//Invoke Remote button

Button invokeButton = (Button)findViewById(R.id.invoke);

invokeButton.setOnClickListener(new onClickListener(){

@Override

public void onClick(View button)

{

if(MainActivity.this.isBound)

{

//Setup the message for invocation

Message message = Message.obtain(null, 1, 0, 0);

try

{

//Set the ReplyTo Messenger for processing the invocation response

message.replyTo = MainActivity.this.replyTo;

//Make the invocation

MainActivity.this.messenger.send(message);

}

catch(RemoteException rme)

{

//Show an Error Message

Toast.makeText(MainActivity.this, "Invocation Failed!!", Toast.LENGTH_LONG).show();

}

}

else

{

Toast.makeText(MainActivity.this, "Service is Not Bound!!", Toast.LENGTH_LONG).show();

}

}

 }

);

}

catch(Exception e)

{

e.printStackTrace(System.out);

}

}

private class RemoteServiceConnection implements ServiceConnection

{

@Override

public void onServiceConnected(ComponentName component, IBinder binder)

{

MainActivity.this.messenger = new Messenger(binder);

MainActivity.this.isBound = true;

}


@Override

public void onServiceDisconnected(ComponentName component)

{

MainActivity.this.messenger = null;

MainActivity.this.isBound = false;

}

}

private class IncomingHandler extends Handler

{

@Override

       public void handleMessage(Message msg)

{

System.out.println("*****************************************");

System.out.println("Return successfully received!!!!!!");

System.out.println("*****************************************");

int what = msg.what;

Toast.makeText(MainActivity.this.getApplicationContext(), "Remote Service replied-("+what+")", Toast.LENGTH_LONG).show();

       }

}

}


728x90
Comments