| page.title=바인딩된 서비스 |
| parent.title=서비스 |
| parent.link=services.html |
| @jd:body |
| |
| |
| <div id="qv-wrapper"> |
| <ol id="qv"> |
| <h2>이 문서의 내용</h2> |
| <ol> |
| <li><a href="#Basics">기본 정보</a></li> |
| <li><a href="#Creating">바인딩된 서비스 생성</a> |
| <ol> |
| <li><a href="#Binder">바인더 클래스 확장</a></li> |
| <li><a href="#Messenger">메신저 사용</a></li> |
| </ol> |
| </li> |
| <li><a href="#Binding">서비스에 바인딩</a></li> |
| <li><a href="#Lifecycle">바인딩된 서비스 수명 주기 관리</a></li> |
| </ol> |
| |
| <h2>Key 클래스</h2> |
| <ol> |
| <li>{@link android.app.Service}</li> |
| <li>{@link android.content.ServiceConnection}</li> |
| <li>{@link android.os.IBinder}</li> |
| </ol> |
| |
| <h2>샘플</h2> |
| <ol> |
| <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code |
| RemoteService}</a></li> |
| <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code |
| LocalService}</a></li> |
| </ol> |
| |
| <h2>참고 항목</h2> |
| <ol> |
| <li><a href="{@docRoot}guide/components/services.html">서비스</a></li> |
| </ol> |
| </div> |
| |
| |
| <p>바인딩된 서비스란 클라이언트 서버 인터페이스 안의 서버를 말합니다. 바인딩된 서비스를 사용하면 구성 요소(활동 등)를 |
| 서비스에 바인딩되게 하거나, 요청을 보내고 응답을 수신하며 심지어는 |
| 프로세스간 통신(IPC)까지 수행할 수 있게 됩니다. 일반적으로 바인딩된 서비스는 다른 애플리케이션 |
| 구성 요소를 도울 때까지만 살고 배경에서 무한히 실행되지 않습니다.</p> |
| |
| <p>이 문서는 다른 애플리케이션 구성 요소의 |
| 서비스에 바인딩하는 방법을 포함하여 바인딩된 서비스를 만드는 방법을 보여줍니다. 하지만 일반적인 서비스에 관한 정보도 알아두는 것이 좋습니다. |
| 서비스에서 알림을 전달하는 방법이나 서비스를 전경에서 실행되도록 설정하는 방법 등 여러 가지 |
| 추가 정보를 알아보려면 <a href="{@docRoot}guide/components/services.html">서비스</a> 문서를 참조하십시오.</p> |
| |
| |
| <h2 id="Basics">기본 정보</h2> |
| |
| <p>바인딩된 서비스란 일종의 {@link android.app.Service} 클래스 구현으로, |
| 이를 통해 다른 애플리케이션이 이 서비스에 바인딩하여 상호 작용할 수 있도록 해주는 것입니다. 한 서비스에 대한 바인딩을 제공하려면, |
| {@link android.app.Service#onBind onBind()} 콜백 메서드를 구현해야 합니다. |
| 이 메서드는 클라이언트가 서비스와 상호 작용하는 데 사용하는 프로그래밍 인터페이스를 정의하는 {@link android.os.IBinder} 개체를 |
| 반환합니다.</p> |
| |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h3>시작된 서비스에 바인딩</h3> |
| |
| <p><a href="{@docRoot}guide/components/services.html">서비스</a> |
| 문서에서 논의된 바와 같이, 시작되었으면서도 바인딩된 서비스를 만들 수 있습니다. 다시 말해, |
| {@link android.content.Context#startService startService()}를 호출하여 서비스를 시작할 수 있으며 |
| 이를 통해 서비스가 무한히 실행되도록 할 수 있으며, {@link |
| android.content.Context#bindService bindService()}를 호출하면 클라이언트가 해당 서비스에 바인딩되도록 할 수 있다는 것입니다. |
| <p>서비스를 시작되고 바인딩되도록 허용한 다음 서비스가 시작되면 |
| 시스템은 클라이언트가 모두 바인딩을 해제해도 서비스를 소멸시키지 <em>않습니다</em>. 대신, |
| 직접 서비스를 확실히 중단시켜야 합니다. 그러려면 {@link android.app.Service#stopSelf stopSelf()} 또는 {@link |
| android.content.Context#stopService stopService()}를 호출하면 됩니다.</p> |
| |
| <p>보통은 {@link android.app.Service#onBind onBind()} |
| <em>또는</em> {@link android.app.Service#onStartCommand onStartCommand()} |
| 중 한 가지만 구현하지만, 둘 모두 구현해야 할 때도 있습니다. 예를 들어, 음악 플레이어의 경우 서비스를 무한히 실행하면서 |
| 바인딩도 제공하도록 허용하는 것이 유용하다는 결론을 내릴 수 있습니다. 이렇게 하면, 한 액티비티가 서비스로 하여금 음악을 재생하도록 |
| 시작한 다음 사용자가 애플리케이션을 떠나더라도 음악을 계속 재생하도록 할 수 있습니다. 그런 다음, 사용자가 애플리케이션으로 |
| 다시 돌아오면 이 액티비티가 서비스를 바인딩하여 재생 제어권을 다시 획득할 수 있습니다.</p> |
| |
| <p><a href="#Lifecycle">바인딩된 서비스 수명 주기 관리 |
| </a> 관련 섹션을 꼭 읽어보십시오. 시작된 서비스에 바인딩을 |
| 추가할 때 서비스 수명 주기에 관한 자세한 정보를 얻을 수 있습니다.</p> |
| </div> |
| </div> |
| |
| <p>클라이언트가 서비스에 바인딩하려면 {@link android.content.Context#bindService |
| bindService()}를 호출하면 됩니다. 이 때, 반드시 {@link |
| android.content.ServiceConnection}의 구현을 제공해야 하며 이것이 서비스와의 연결을 모니터링합니다. {@link |
| android.content.Context#bindService bindService()} 메서드는 값 없이 즉시 반환됩니다. |
| 그러나 Android 시스템이 클라이언트와 서비스 사이의 |
| 연결을 만드는 경우, 시스템은 {@link |
| android.content.ServiceConnection#onServiceConnected onServiceConnected()}를 {@link |
| android.content.ServiceConnection}에서 호출하여 클라이언트가 서비스와 통신하는 데 사용할 수 있도록 {@link android.os.IBinder}를 |
| 전달하게 됩니다.</p> |
| |
| <p>여러 클라이언트가 한 번에 서비스에 연결될 수 있습니다. 그러나, 시스템이 서비스의 |
| {@link android.app.Service#onBind onBind()} 메서드를 호출하여 {@link android.os.IBinder}를 검색하는 경우는 첫 번째 클라이언트가 |
| 바인딩되는 경우뿐입니다. 시스템은 그 후 같은 {@link android.os.IBinder}를 바인딩되는 추가 |
| 클라이언트 모두에 전달하며 이때는 {@link android.app.Service#onBind onBind()}를 다시 호출하지 않습니다.</p> |
| |
| <p>마지막 클라이언트가 서비스에서 바인딩을 해제하면 시스템은 서비스를 소멸시킵니다( |
| {@link android.content.Context#startService startService()}가 서비스를 시작했을 경우 제외).</p> |
| |
| <p>바인딩된 서비스를 구현할 때 가장 중요한 부분은 |
| {@link android.app.Service#onBind onBind()} 콜백 메서드가 반환하는 인터페이스를 정의하는 것입니다. |
| 서비스의 {@link android.os.IBinder} 인터페이스를 정의하는 방법에는 몇 가지가 있고, 다음 |
| 섹션에서는 각 기법에 관해 논의합니다.</p> |
| |
| |
| |
| <h2 id="Creating">바인딩된 서비스 생성</h2> |
| |
| <p>바인딩을 제공하는 서비스를 생성할 때는 클라이언트가 서비스와 상호 작용하는 데 사용할 수 있는 프로그래밍 인터페이스를 제공하는 {@link android.os.IBinder} |
| 를 제공해야 합니다. |
| 인터페이스를 정의하는 방법은 세 가지가 있습니다.</p> |
| |
| <dl> |
| <dt><a href="#Binder">바인더 클래스 확장</a></dt> |
| <dd>서비스가 본인의 애플리케이션 전용이며 클라이언트와 같은 과정으로 실행되는 |
| 경우(이런 경우가 흔함), 인터페이스를 생성할 때 {@link android.os.Binder} 클래스를 |
| 확장하고 그 인스턴스를 |
| {@link android.app.Service#onBind onBind()}에서 반환하는 방식을 사용해야 합니다. 클라이언트가 {@link android.os.Binder}를 받으며, |
| 이를 사용하여 {@link android.os.Binder} 구현 또는 심지어 {@link android.app.Service}에서 |
| 사용할 수 있는 공개 메서드에 직접 액세스할 수 있습니다. |
| <p>이것은 서비스가 본인의 애플리케이션을 위해 단순히 배경에서 작동하는 요소에 그치는 경우 |
| 선호되는 기법입니다. 인터페이스를 생성할 때 이 방식을 사용하지 않는 유일한 이유는 |
| 서비스를 다른 애플리케이션에서나 별도의 프로세스에 걸쳐 사용하고 있는 경우뿐입니다.</dd> |
| |
| <dt><a href="#Messenger">메신저 사용</a></dt> |
| <dd>인터페이스를 여러 프로세스에 걸쳐 적용되도록 해야 하는 경우, 서비스에 대한 |
| 인터페이스를 {@link android.os.Messenger}로 생성할 수 있습니다. |
| 이 방식을 사용하면 서비스가 여러 가지 유형의 {@link |
| android.os.Message} 개체에 응답하는 {@link android.os.Handler}를 정의합니다. 이 {@link android.os.Handler} |
| 가 {@link android.os.Messenger}의 기초이며, 이를 통해 클라이언트와 함께 {@link android.os.IBinder} |
| 를 공유할 수 있게 되어 클라이언트가 {@link |
| android.os.Message} 개체를 사용해 서비스에 명령을 보낼 수 있게 해줍니다. 이외에도, 클라이언트가 자체적으로 {@link android.os.Messenger}를 |
| 정의하여 서비스가 메시지를 돌려보낼 수 있도록 할 수도 있습니다. |
| <p>이것이 프로세스간 통신(IPC)을 수행하는 가장 간단한 방법입니다. {@link |
| android.os.Messenger}가 모든 요청을 단일 스레드에 대기하게 해서, 서비스를 스레드로부터 안전하게 |
| 설계하지 않아도 되기 때문입니다.</p> |
| </dd> |
| |
| <dt>AIDL 사용하기</dt> |
| <dd>AIDL(Android Interface Definition Language)은 개체를 운영 체제가 이해할 수 있는 |
| 원시 데이터로 구성 해제한 다음 여러 프로세스에 걸쳐 집결하여 IPC를 수행하기 위해 |
| 필요한 모든 작업을 수행합니다. 이전 기법은 {@link android.os.Messenger}를 사용했는데, |
| 사실 그 기본 구조가 AIDL을 기반으로 하고 있는 것입니다. 위에서 언급한 바와 같이 {@link android.os.Messenger}는 단일 스레드에 모든 클라이언트 요청 |
| 대기열을 생성하므로 서비스는 한 번에 요청을 하나씩 수신합니다. 그러나, |
| 서비스가 동시에 여러 요청을 처리하도록 하고 싶은 경우에는 AIDL을 직접 사용해도 |
| 됩니다. 이 경우, 서비스가 다중 스레딩을 할 수 있어야 하며 스레드로부터 안전하게 구축되었어야 합니다. |
| <p>AIDL을 직접 사용하려면 |
| 프로그래밍 인터페이스를 정의하는 {@code .aidl} 파일을 생성해야 합니다. Android SDK 도구는 |
| 이 파일을 사용하여 인터페이스를 구현하고 IPC를 처리하는 추상 클래스를 생성하고, |
| 그러면 개발자가 직접 이것을 서비스 내에서 확장하면 됩니다.</p> |
| </dd> |
| </dl> |
| |
| <p class="note"><strong>참고:</strong> 대부분의 애플리케이션의 경우, |
| 바인딩된 서비스를 생성하기 위해 AIDL를 사용해서는 <strong>안 됩니다</strong>. |
| 그러려면 다중 스레딩 기능이 필요할 수 있고, 따라서 더 복잡한 구현을 초래할 수 있기 때문입니다. 따라서 AIDL은 |
| 대부분의 애플리케이션에 적합하지 않으므로 이 문서에서는 여러분의 서비스에 이를 이용하는 방법에 대해 다루지 않습니다. AIDL을 직접 사용해야 한다는 확신이 드는 경우, |
| <a href="{@docRoot}guide/components/aidl.html">AIDL</a> 문서를 참조하십시오. |
| </p> |
| |
| |
| |
| |
| <h3 id="Binder">바인더 클래스 확장</h3> |
| |
| <p>서비스를 사용하는 것이 로컬 애플리케이션뿐이고 여러 프로세스에 걸쳐 작동할 필요가 없는 경우, |
| 나름의 {@link android.os.Binder} 클래스를 구현하여 |
| 클라이언트로 하여금 서비스 내의 공개 메서드에 직접 액세스할 수 있도록 할 수도 있습니다.</p> |
| |
| <p class="note"><strong>참고:</strong> 이것은 클라이언트와 서비스가 |
| 같은 애플리케이션 및 프로세스에 있는 경우에만 통하며, 이 경우가 가장 보편적입니다. 이 방식이 잘 통하는 경우를 예로 들면, |
| 음악 애플리케이션에서 자체 서비스에 액티비티를 바인딩하여 배경에서 음악을 재생하도록 해야 하는 |
| 경우가 있습니다.</p> |
| |
| <p>이렇게 설정하는 방법은 다음과 같습니다.</p> |
| <ol> |
| <li>서비스에서 다음 중 한 가지에 해당하는 {@link android.os.Binder}의 인스턴스를 생성합니다. |
| <ul> |
| <li>클라이언트가 호출할 수 있는 공개 메서드 포함</li> |
| <li>클라이언트가 호출할 수 있는 공개 메서드가 있는 현재{@link android.app.Service} |
| 인스턴스를 반환</li> |
| <li>클라이언트가 호출할 수 있는 공개 메서드가 포함된 서비스가 호스팅하는 다른 클래스의 인스턴스를 반환 |
| </li> |
| </ul> |
| <li>{@link |
| android.app.Service#onBind onBind()} 콜백 메서드에서 이 {@link android.os.Binder}의 인스턴스를 반환합니다.</li> |
| <li>클라이언트의 경우, {@link android.os.Binder}를 {@link |
| android.content.ServiceConnection#onServiceConnected onServiceConnected()} |
| 콜백 메서드에서 받아 제공된 메서드를 사용해 서비스를 바인딩하기 위해 호출합니다.</li> |
| </ol> |
| |
| <p class="note"><strong>참고:</strong> 서비스와 클라이언트가 같은 애플리케이션에 |
| 있어야 하는 것은 그래야만 클라이언트가 반환된 개체를 캐스팅하여 해당 API를 적절하게 호출할 수 있기 때문입니다. 또한 |
| 서비스와 클라이언트는 같은 프로세스에 있어야 하기도 합니다. 이 기법에서는 |
| 여러 프로세스에 걸친 집결 작업을 전혀 수행하지 않기 때문입니다.</p> |
| |
| <p>예컨대, 어떤 서비스가 클라이언트에게 {@link android.os.Binder} 구현을 통해 서비스 내의 |
| 메서드에 액세스할 수 있도록 한다고 합시다.</p> |
| |
| <pre> |
| public class LocalService extends Service { |
| // Binder given to clients |
| private final IBinder mBinder = new LocalBinder(); |
| // Random number generator |
| private final Random mGenerator = new Random(); |
| |
| /** |
| * Class used for the client Binder. Because we know this service always |
| * runs in the same process as its clients, we don't need to deal with IPC. |
| */ |
| public class LocalBinder extends Binder { |
| LocalService getService() { |
| // Return this instance of LocalService so clients can call public methods |
| return LocalService.this; |
| } |
| } |
| |
| @Override |
| public IBinder onBind(Intent intent) { |
| return mBinder; |
| } |
| |
| /** method for clients */ |
| public int getRandomNumber() { |
| return mGenerator.nextInt(100); |
| } |
| } |
| </pre> |
| |
| <p>{@code LocalBinder}는 클라이언트에게 {@code LocalService}의 현재 인스턴스를 검색하기 위한 {@code getService()} 메서드 |
| 를 제공합니다. 이렇게 하면 클라이언트가 서비스 내의 공개 메서드를 호출할 수 있습니다. |
| 클라이언트는 예컨대 서비스에서 {@code getRandomNumber()}를 호출할 수 있습니다.</p> |
| |
| <p>다음은 버튼을 클릭했을 때 {@code LocalService}에 바인딩되며 {@code getRandomNumber()} |
| 를 호출하는 액티비티를 나타낸 것입니다.</p> |
| |
| <pre> |
| public class BindingActivity extends Activity { |
| LocalService mService; |
| boolean mBound = false; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.main); |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| // Bind to LocalService |
| Intent intent = new Intent(this, LocalService.class); |
| bindService(intent, mConnection, Context.BIND_AUTO_CREATE); |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| // Unbind from the service |
| if (mBound) { |
| unbindService(mConnection); |
| mBound = false; |
| } |
| } |
| |
| /** Called when a button is clicked (the button in the layout file attaches to |
| * this method with the android:onClick attribute) */ |
| public void onButtonClick(View v) { |
| if (mBound) { |
| // Call a method from the LocalService. |
| // However, if this call were something that might hang, then this request should |
| // occur in a separate thread to avoid slowing down the activity performance. |
| int num = mService.getRandomNumber(); |
| Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show(); |
| } |
| } |
| |
| /** Defines callbacks for service binding, passed to bindService() */ |
| private ServiceConnection mConnection = new ServiceConnection() { |
| |
| @Override |
| public void onServiceConnected(ComponentName className, |
| IBinder service) { |
| // We've bound to LocalService, cast the IBinder and get LocalService instance |
| LocalBinder binder = (LocalBinder) service; |
| mService = binder.getService(); |
| mBound = true; |
| } |
| |
| @Override |
| public void onServiceDisconnected(ComponentName arg0) { |
| mBound = false; |
| } |
| }; |
| } |
| </pre> |
| |
| <p>위 예시는 클라이언트가 |
| {@link android.content.ServiceConnection} 구현과 {@link |
| android.content.ServiceConnection#onServiceConnected onServiceConnected()} 콜백을 사용하여 서비스에 바인딩하는 방법을 보여줍니다. 다음 |
| 섹션에서는 서비스에 바인딩하는 이러한 과정에 대해 좀 더 자세한 정보를 제공합니다.</p> |
| |
| <p class="note"><strong>참고:</strong> 위 예시에서는 서비스에서 분명히 바인딩을 해제하지는 않습니다. |
| 그러나 모든 클라이언트는 적절한 시점에 바인딩을 해제해야 합니다(액티비티가 일시 중지될 때 등).</p> |
| |
| <p>더 많은 샘플 코드를 보려면 <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>에서 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code |
| LocalService.java}</a> 클래스와 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code |
| LocalServiceActivities.java}</a> 클래스를 참조하십시오.</p> |
| |
| |
| |
| |
| |
| <h3 id="Messenger">메신저 사용</h3> |
| |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h4>AIDL과 비교</h4> |
| <p>IPC를 수행해야 할 경우, 인터페이스에 대해 {@link android.os.Messenger}를 사용하는 것이 |
| AIDL로 구현하는 것보다 간단합니다. 왜냐하면 {@link android.os.Messenger}는 |
| 모든 호출을 서비스에 대기시키지만 순수한 AIDL 인터페이스는 |
| 서비스에 동시에 요청을 전송하여 다중 스레딩을 처리해야 하기 때문입니다.</p> |
| <p>대부분의 애플리이션에서는 서비스가 다중 스레딩을 수행할 필요가 없으므로 {@link |
| android.os.Messenger}를 사용하면 호출을 한 번에 하나씩 처리할 수 있습니다. 서비스가 |
| 다중 스레딩되는 것이 중요한 경우, 인터페이스를 정의하는 데 <a href="{@docRoot}guide/components/aidl.html">AIDL</a>을 사용해야 합니다.</p> |
| </div> |
| </div> |
| |
| <p>서비스가 원격 프로세스와 통신해야 한다면 서비스에 인터페이스를 제공하는 데 |
| {@link android.os.Messenger}를 사용하면 됩니다. 이 기법을 사용하면 |
| AIDL을 쓰지 않고도 프로세스간 통신(IPC)을 수행할 수 있게 해줍니다.</p> |
| |
| <p>다음은 {@link android.os.Messenger} 사용 방법을 간략하게 요약한 것입니다.</p> |
| |
| <ul> |
| <li>서비스가 클라이언트로부터 각 호출에 대해 콜백을 받는 {@link android.os.Handler}를 |
| 구현합니다.</li> |
| <li>{@link android.os.Handler}를 사용하여 {@link android.os.Messenger} 개체를 생성합니다 |
| (이것은 {@link android.os.Handler}에 대한 참조입니다).</li> |
| <li>{@link android.os.Messenger}가 {@link android.os.IBinder}를 생성하여 서비스가 |
| {@link android.app.Service#onBind onBind()}로부터 클라이언트에게 반환하도록 합니다.</li> |
| <li>클라이언트는 {@link android.os.IBinder}를 사용하여 {@link android.os.Messenger} |
| (서비스의 {@link android.os.Handler}를 참조)를 인스턴트화하고, 이를 이용하여 |
| {@link android.os.Message} 개체를 서비스에 전송합니다.</li> |
| <li>서비스가 각 {@link android.os.Message}를 {@link |
| android.os.Handler}로 수신합니다. 구체적으로는 {@link android.os.Handler#handleMessage |
| handleMessage()} 메서드를 사용합니다.</li> |
| </ul> |
| |
| |
| <p>이렇게 하면, 클라이언트가 서비스에서 호출할 "메서드"가 없습니다. 대신 클라이언트는 |
| "메시지"({@link android.os.Message} 개체)를 전달하여 서비스가 |
| {@link android.os.Handler}로 받을 수 있도록 합니다.</p> |
| |
| <p>다음은 {@link android.os.Messenger} 인터페이스를 사용하는 간단한 예시 서비스입니다.</p> |
| |
| <pre> |
| public class MessengerService extends Service { |
| /** Command to the service to display a message */ |
| static final int MSG_SAY_HELLO = 1; |
| |
| /** |
| * Handler of incoming messages from clients. |
| */ |
| class IncomingHandler extends Handler { |
| @Override |
| public void handleMessage(Message msg) { |
| switch (msg.what) { |
| case MSG_SAY_HELLO: |
| Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); |
| break; |
| default: |
| super.handleMessage(msg); |
| } |
| } |
| } |
| |
| /** |
| * Target we publish for clients to send messages to IncomingHandler. |
| */ |
| final Messenger mMessenger = new Messenger(new IncomingHandler()); |
| |
| /** |
| * When binding to the service, we return an interface to our messenger |
| * for sending messages to the service. |
| */ |
| @Override |
| public IBinder onBind(Intent intent) { |
| Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); |
| return mMessenger.getBinder(); |
| } |
| } |
| </pre> |
| |
| <p>{@link android.os.Handler}의 {@link android.os.Handler#handleMessage handleMessage()} 메서드에서 |
| 서비스가 수신되는 {@link android.os.Message}를 받고 |
| {@link android.os.Message#what} 구성원에 기초하여 무엇을 할지 결정한다는 점을 눈여겨 보십시오.</p> |
| |
| <p>클라이언트는 서비스가 반환한 {@link |
| android.os.IBinder}에 기초하여 {@link android.os.Messenger}를 생성하고 {@link |
| android.os.Messenger#send send()}로 메시지를 전송하기만 하면 됩니다. 예를 들어, 다음은 |
| 서비스에 바인딩하여 {@code MSG_SAY_HELLO} 메시지를 서비스에 전달하는 간단한 액티비티입니다.</p> |
| |
| <pre> |
| public class ActivityMessenger extends Activity { |
| /** Messenger for communicating with the service. */ |
| Messenger mService = null; |
| |
| /** Flag indicating whether we have called bind on the service. */ |
| boolean mBound; |
| |
| /** |
| * Class for interacting with the main interface of the service. |
| */ |
| private ServiceConnection mConnection = new ServiceConnection() { |
| public void onServiceConnected(ComponentName className, IBinder service) { |
| // This is called when the connection with the service has been |
| // established, giving us the object we can use to |
| // interact with the service. We are communicating with the |
| // service using a Messenger, so here we get a client-side |
| // representation of that from the raw IBinder object. |
| mService = new Messenger(service); |
| mBound = true; |
| } |
| |
| public void onServiceDisconnected(ComponentName className) { |
| // This is called when the connection with the service has been |
| // unexpectedly disconnected -- that is, its process crashed. |
| mService = null; |
| mBound = false; |
| } |
| }; |
| |
| public void sayHello(View v) { |
| if (!mBound) return; |
| // Create and send a message to the service, using a supported 'what' value |
| Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); |
| try { |
| mService.send(msg); |
| } catch (RemoteException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.main); |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| // Bind to the service |
| bindService(new Intent(this, MessengerService.class), mConnection, |
| Context.BIND_AUTO_CREATE); |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| // Unbind from the service |
| if (mBound) { |
| unbindService(mConnection); |
| mBound = false; |
| } |
| } |
| } |
| </pre> |
| |
| <p>이 예시에는 서비스가 클라이언트에 응답하는 방식이 나타나 있지 않다는 것을 유념하십시오. 서비스가 응답하게 하려면 |
| 클라이언트에도 {@link android.os.Messenger}를 생성해야 합니다. |
| 클라이언트가 {@link android.content.ServiceConnection#onServiceConnected |
| onServiceConnected()} 콜백을 받으면 {@link android.os.Messenger#send send()}메서드의 {@link android.os.Message#replyTo} 매개변수에서 클라이언트의 {@link android.os.Messenger}를 포함하는 {@link android.os.Message}를 |
| 서비스에 전송합니다. |
| </p> |
| |
| <p>양방향 메시지를 제공하는 방법의 예시는 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code |
| MessengerService.java}</a>(서비스) 및 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code |
| MessengerServiceActivities.java}</a>(클라이언트) 예시를 참조하십시오.</p> |
| |
| |
| |
| |
| |
| <h2 id="Binding">서비스에 바인딩</h2> |
| |
| <p>애플리케이션 구성 요소(클라이언트)를 서비스에 바인딩하려면 |
| {@link android.content.Context#bindService bindService()}를 호출하면 됩니다. 그러면 Android |
| system이 서비스의 {@link android.app.Service#onBind |
| onBind()} 메서드를 호출하고, 이는 서비스와의 상호 작용을 위해 {@link android.os.IBinder}를 반환합니다.</p> |
| |
| <p>바인딩은 비동기식입니다. {@link android.content.Context#bindService |
| bindService()}는 즉시 반환하고 클라이언트에게 {@link android.os.IBinder}를 반환하지 <em>않습니다</em>. |
| {@link android.os.IBinder}를 수신하려면 클라이언트는 {@link |
| android.content.ServiceConnection}의 인스턴스를 생성하여 이를 {@link android.content.Context#bindService |
| bindService()}에 전달해야 합니다. {@link android.content.ServiceConnection}에는 |
| {@link android.os.IBinder}를 전달하기 위해 시스템이 호출하는 콜백 메서드가 포함됩니다.</p> |
| |
| <p class="note"><strong>참고:</strong> 서비스에 바인딩할 수 있는 것은 액티비티, 서비스 및 |
| 콘텐츠 제공자뿐입니다. 브로드캐스트 수신자로부터는 서비스에 바인딩할 수 <strong>없습니다</strong>.</p> |
| |
| <p>따라서, 클라이언트로부터 서비스에 바인딩하려면 다음과 같이 해야 합니다. </p> |
| <ol> |
| <li>{@link android.content.ServiceConnection}을 구현합니다. |
| <p>이 구현으로 두 가지 콜백 메서드를 재정의해야 합니다.</p> |
| <dl> |
| <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt> |
| <dd>시스템이 이것을 호출하여 서비스의 |
| {@link android.app.Service#onBind onBind()} 메서드가 반환한 {@link android.os.IBinder}를 전달합니다.</dd> |
| <dt>{@link android.content.ServiceConnection#onServiceDisconnected |
| onServiceDisconnected()}</dt> |
| <dd>Android 시스템이 이것을 호출하는 경우는 서비스로의 연결이 |
| 예기치 못하게 끊어졌을 때, 즉 서비스가 충돌했거나 중단되었을 때 등입니다. |
| 클라이언트가 바인딩을 해제한다고 이것이 호출되지는 <em>않습니다</em>.</dd> |
| </dl> |
| </li> |
| <li>{@link |
| android.content.Context#bindService bindService()}를 호출하고 {@link |
| android.content.ServiceConnection} 구현을 전달합니다. </li> |
| <li>시스템이 {@link android.content.ServiceConnection#onServiceConnected |
| onServiceConnected()} 콜백 메서드를 호출하면, 인터페이스가 정의한 메서드를 사용하여 |
| 서비스에 호출을 시작해도 됩니다.</li> |
| <li>서비스로부터 연결을 해제하려면 {@link |
| android.content.Context#unbindService unbindService()}를 호출합니다. |
| <p>클라이언트가 소멸되면 이는 서비스에서 바인딩을 해제하게 되지만, |
| 서비스와 상호 작용을 마쳤을 때 또는 액티비티가 일시 중지되었을 때에는 항상 바인딩을 해제해야 합니다. |
| 이렇게 해야 서비스가 사용 중이 아닐 때에는 중지할 수 있습니다 |
| (바인딩과 바인딩 해제의 적절한 시기는 아래에서 좀 더 논의합니다).</p> |
| </li> |
| </ol> |
| |
| <p>예를 들어, 다음 코드 조각은 위와 같이 |
| <a href="#Binder">바인더 클래스를 확장해서</a> 생성한 서비스와 클라이언트를 연결합니다. 그러므로 이것이 해야 하는 일은 반환된 |
| {@link android.os.IBinder}를 {@code LocalService} 클래스에 캐스팅하고 {@code |
| LocalService} 인스턴스를 요청하는 것뿐입니다.</p> |
| |
| <pre> |
| LocalService mService; |
| private ServiceConnection mConnection = new ServiceConnection() { |
| // Called when the connection with the service is established |
| public void onServiceConnected(ComponentName className, IBinder service) { |
| // Because we have bound to an explicit |
| // service that is running in our own process, we can |
| // cast its IBinder to a concrete class and directly access it. |
| LocalBinder binder = (LocalBinder) service; |
| mService = binder.getService(); |
| mBound = true; |
| } |
| |
| // Called when the connection with the service disconnects unexpectedly |
| public void onServiceDisconnected(ComponentName className) { |
| Log.e(TAG, "onServiceDisconnected"); |
| mBound = false; |
| } |
| }; |
| </pre> |
| |
| <p>이 {@link android.content.ServiceConnection}이 있으면 클라이언트는 |
| 이것을 {@link android.content.Context#bindService bindService()}에 전달하여 서비스에 바인딩할 수 있습니다. 예:</p> |
| |
| <pre> |
| Intent intent = new Intent(this, LocalService.class); |
| bindService(intent, mConnection, Context.BIND_AUTO_CREATE); |
| </pre> |
| |
| <ul> |
| <li>{@link android.content.Context#bindService bindService()}의 첫 번째 매개변수는 바인딩할 서비스를 명시적으로 명명하는 |
| {@link android.content.Intent}입니다(인텐트는 |
| 암시적일 수 있음).</li> |
| <li>두 번째 매개변수는 {@link android.content.ServiceConnection} 개체입니다.</li> |
| <li>세 번째 매개변수는 바인딩 옵션을 나타내는 플래그입니다. 서비스를 생성하기 위해 보통은 {@link |
| android.content.Context#BIND_AUTO_CREATE}를 사용합니다(이미 살아 있는 상태가 아닌 경우). |
| 가능한 기타 값은 {@link android.content.Context#BIND_DEBUG_UNBIND} |
| 및 {@link android.content.Context#BIND_NOT_FOREGROUND}, 또는 값이 없는 경우 {@code 0}입니다.</li> |
| </ul> |
| |
| |
| <h3>추가 참고 사항</h3> |
| |
| <p>다음은 서비스에 바인딩하는 데 관한 몇 가지 중요한 참고 사항입니다.</p> |
| <ul> |
| <li>항상 {@link android.os.DeadObjectException} 예외를 트래핑해야 합니다. |
| 이것은 연결이 끊어지면 발생합니다. 원격 메서드에 의해 발생하는 예외는 이것뿐입니다.</li> |
| <li>개체는 여러 프로세스에 걸쳐 감안된 참조입니다. </li> |
| <li>일반적으로, 클라이언트의 수명 주기를 |
| 결합하고 분해하는 순간을 일치시키면서 바인딩과 바인딩 해제를 페어링해야 합니다. 예: |
| <ul> |
| <li>액티비티가 눈에 보이는 동안에만 서비스와 상호 작용해야 한다면 |
| {@link android.app.Activity#onStart onStart()}에는 바인딩하고 {@link |
| android.app.Activity#onStop onStop()}에는 바인딩을 해제해야 합니다.</li> |
| <li> |
| 배경에서 중단되었을 때도 액티비티가 응답을 받게 하고 싶다면 {@link android.app.Activity#onCreate onCreate()}에는 바인딩하고 |
| {@link android.app.Activity#onDestroy onDestroy()} 중에는 바인딩을 해제합니다. |
| 이때, 사용자의 액티비티가 서비스가 실행되는 시간 전체에서(배경에서라도) 서비스를 사용한다는 것을 유념해야 합니다. |
| 서비스가 다른 프로세스에 있을 경우, 사용자가 프로세스의 가중치를 높이면 시스템이 |
| 이를 중단할 가능성이 높아집니다.</li> |
| </ul> |
| <p class="note"><strong>참고:</strong> 일반적으로는, 액티비티의 {@link android.app.Activity#onResume onResume()}와 {@link |
| android.app.Activity#onPause onPause()}에는 바인딩하거나 바인딩을 해제하지 <strong>말아야</strong> 합니다. 이러한 콜백은 모든 수명 주기 전환에서 발생하고 |
| 이런 전환에서 발생하는 처리는 |
| 최소한으로 유지해야 하기 때문입니다. 또한, |
| 사용자 애플리케이션의 여러 액티비티가 동일한 서비스에 바인딩되었고 |
| 두 액티비티 사이에 전환이 있을 경우, 현재 액티비티의 바인딩이 해제된 후(일시중지 중) 다음 액티비티가 바인딩하기 전(재개 중)에 |
| 서비스가 제거되었다가 다시 생성될 수 있습니다 (수명 주기를 조절하기 위한 이러한 액티비티 전환은 |
| <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">액티비티</a> |
| 문서에 설명되어 있습니다).</p> |
| </ul> |
| |
| <p>더 많은 샘플 코드를 보려면 <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>의 <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code |
| RemoteService.java}</a> 클래스를 참조하십시오.</p> |
| |
| |
| |
| |
| |
| <h2 id="Lifecycle">바인딩된 서비스 수명 주기 관리</h2> |
| |
| <p>서비스가 모든 클라이언트로부터 바인딩 해제되면, Android 시스템이 이를 소멸시킵니다(다만 |
| {@link android.app.Service#onStartCommand onStartCommand()}와도 함께 시작된 경우는 예외). |
| 따라서, 서비스가 순전히 바인딩된 서비스일 경우에는 해당 서비스의 수명 주기를 관리하지 않아도 됩니다. |
| 클라이언트에 바인딩되었는지를 근거로 Android 시스템이 대신 관리해주기 때문입니다.</p> |
| |
| <p>그러나 {@link android.app.Service#onStartCommand |
| onStartCommand()} 콜백 메서드를 구현하기로 선택하는 경우라면 서비스를 확실히 중지해야 합니다. |
| 서비스가 현재 <em>시작된 것</em>으로 간주되기 때문입니다. 이런 경우, 서비스는 클라이언트에 바인딩되었는지 여부와 관계없이 |
| {@link android.app.Service#stopSelf()}와 함께 스스로 중단되거나 다른 구성 요소가{@link |
| android.content.Context#stopService stopService()}를 호출할 때까지 실행됩니다. |
| </p> |
| |
| <p>또한, 서비스가 시작되고 바인딩을 허용할 경우 시스템이 |
| {@link android.app.Service#onUnbind onUnbind()} 메서드를 호출하면 |
| {@code true}를 선택적으로 반환할 수 있습니다. 다음에 클라이언트가 서비스에 바인딩할 때({@link |
| android.app.Service#onBind onBind()}에 대한 호출을 수신하지 않고) {@link android.app.Service#onRebind |
| onRebind()}에 대한 호출을 받을지 여부에 따라 결정됩니다. {@link android.app.Service#onRebind |
| onRebind()}가 void를 반환하였지만 클라이언트가 |
| {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} 콜백에서 {@link android.os.IBinder}를 여전히 수신합니다. |
| 아래 그림 1은 이런 수명 주기의 논리를 나타냅니다.</p> |
| |
| |
| <img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" /> |
| <p class="img-caption"><strong>그림 1.</strong> 시작되었으며 바인딩도 허용하는 서비스의 수명 주기입니다. |
| </p> |
| |
| |
| <p>시작된 서비스의 수명 주기에 관한 자세한 정보는 <a href="{@docRoot}guide/components/services.html#Lifecycle">서비스</a> 문서를 참조하십시오.</p> |
| |
| |
| |
| |