| page.title=서비스 |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <ol id="qv"> |
| <h2>이 문서의 내용</h2> |
| <ol> |
| <li><a href="#Basics">기본 정보</a></li> |
| <ol> |
| <li><a href="#Declaring">매니페스트에서 서비스 선언하기</a></li> |
| </ol> |
| <li><a href="#CreatingAService">시작된 서비스 생성하기</a> |
| <ol> |
| <li><a href="#ExtendingIntentService">IntentService 클래스 확장하기</a></li> |
| <li><a href="#ExtendingService">서비스 클래스 확장하기</a></li> |
| <li><a href="#StartingAService">서비스 시작</a></li> |
| <li><a href="#Stopping">서비스 중단</a></li> |
| </ol> |
| </li> |
| <li><a href="#CreatingBoundService">바인딩된 서비스 생성</a></li> |
| <li><a href="#Notifications">사용자에게 알림 전송</a></li> |
| <li><a href="#Foreground">전경에서 서비스 실행하기</a></li> |
| <li><a href="#Lifecycle">서비스 수명 주기 관리</a> |
| <ol> |
| <li><a href="#LifecycleCallbacks">수명 주기 콜백 구현하기</a></li> |
| </ol> |
| </li> |
| </ol> |
| |
| <h2>Key 클래스</h2> |
| <ol> |
| <li>{@link android.app.Service}</li> |
| <li>{@link android.app.IntentService}</li> |
| </ol> |
| |
| <h2>샘플</h2> |
| <ol> |
| <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/ServiceStartArguments.html">{@code |
| ServiceStartArguments}</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/bound-services.html">바인딩된 서비스</a></li> |
| </ol> |
| |
| </div> |
| |
| |
| <p>{@link android.app.Service}는 배경에서 오래 실행되는 작업을 |
| 수행할 수 있는 애플리케이션 구성 요소이며 사용자 인터페이스를 제공하지 않습니다. 또 다른 |
| 애플리케이션 구성 요소가 서비스를 시작할 수 있으며, 이는 사용자가 또 다른 |
| 애플리케이션으로 전환하더라도 배경에서 계속해서 실행됩니다. 이외에도, 구성 요소를 서비스에 바인딩하여 |
| 서비스와 상호 작용할 수 있으며, 심지어는 프로세스 간 통신(IPC)도 수행할 수 있습니다. 예를 들어 한 서비스는 |
| 네트워크 트랜잭션을 처리하고, 음악을 재생하고 파일 I/O를 수행하거나 콘텐츠 제공자와 상호 작용할 수 있으며 |
| 이 모든 것을 배경에서 수행할 수 있습니다.</p> |
| |
| <p>서비스는 본질적으로 두 가지 형식을 취합니다.</p> |
| |
| <dl> |
| <dt>시작됨</dt> |
| <dd>서비스가 "시작된" 상태가 되려면 애플리케이션 구성 요소(예: 액티비티)가 |
| {@link android.content.Context#startService startService()}를 호출하여 시작하면 됩니다. 서비스는 한 번 시작되고 나면 |
| 배경에서 무기한으로 실행될 수 있으며, 이는 해당 서비스를 시작한 구성 요소가 소멸되었더라도 무관합니다. 보통, |
| 시작된 서비스는 한 작업을 수행하고 결과를 발신자에게 반환하지 않습니다. |
| 예를 들어 네트워크에서 파일을 다운로드하거나 업로드할 수 있습니다. 작업을 완료하면, 해당 서비스는 |
| 알아서 중단되는 것이 정상입니다.</dd> |
| <dt>바인딩됨</dt> |
| <dd>서비스가 "바인딩된" 상태가 되려면 애플리케이션 구성 요소가 {@link |
| android.content.Context#bindService bindService()}를 사용하여 해당 서비스에 바인딩되면 됩니다. 바인딩된 서비스는 클라이언트-서버 |
| 인터페이스를 제공하여 구성 요소가 서비스와 상호 작용할 수 있도록 해주며, 결과를 가져올 수도 있고 심지어 |
| 이와 같은 작업을 여러 프로세스에 걸쳐 프로세스 간 통신(IPC)으로 수행할 수도 있습니다. 바인딩된 서비스는 또 다른 애플리케이션 구성 요소가 |
| 이에 바인딩되어 있는 경우에만 실행됩니다. 여러 개의 구성 요소가 서비스에 한꺼번에 바인딩될 수 있지만, |
| 이 모든 것이 바인딩을 해제하면 해당 서비스는 소멸됩니다.</dd> |
| </dl> |
| |
| <p>이 문서는 주로 이러한 두 가지 유형의 서비스를 따로따로 논하지만, 서비스는 |
| 두 가지 방식 모두로 작동할 수 있습니다. 즉 서비스가 시작될 수도 있고(나아가 무기한으로 실행되고) 바인딩도 허용할 수 있다는 뜻입니다. |
| 이는 그저 두어 가지 콜백 메서드의 구현 여부에 달린 문제입니다. {@link |
| android.app.Service#onStartCommand onStartCommand()}를 사용하면 구성 요소가 서비스를 시작할 수 있게 허용하고, {@link |
| android.app.Service#onBind onBind()}를 사용하면 바인딩을 허용합니다.</p> |
| |
| <p>애플리케이션이 시작되었든, 바인딩되었든 아니면 양쪽 모두이든 모든 애플리케이션 구성 요소가 |
| 해당 서비스를 사용할 수 있으며(별도의 애플리케이션에서라도), 이는 어느 구성 요소든 액티비티를 |
| 사용할 수 있는 것과 같습니다. 이를 {@link android.content.Intent}로 시작하면 됩니다. 그러나, |
| 매니페스트에서 서비스를 비공개로 선언하고 다른 애플리케이션으로부터의 액세스를 차단할 수도 있습니다. 이것은 |
| <a href="#Declaring">매니페스트에서 서비스 |
| 선언하기</a>에 관한 섹션에서 더 자세히 이야기합니다.</p> |
| |
| <p class="caution"><strong>주의:</strong> 서비스는 자신의 호스팅 프로세스의 |
| 기본 스레드에서 실행됩니다. 서비스는 자신의 스레드를 직접 생성하지 <strong>않으며</strong>, |
| 별도의 프로세스에서 실행되지도 <strong>않습니다</strong>(별도로 지정하는 경우는 예외). 이것은 즉, |
| 서비스가 CPU 집약적인 작업을 수행할 예정이거나 차단적인 작업을 수행할 예정인 경우(예를 들어 MP3 |
| 재생 또는 네트워킹 등), 서비스 내에 새 스레드를 생성하여 해당 작업을 수행하도록 해야 한다는 뜻입니다. 별도의 스레드를 사용하면 |
| '애플리케이션이 응답하지 않습니다(ANR)' 오류가 일어날 위험을 줄일 수 있으며 |
| 애플리케이션의 기본 스레드는 액티비티와 사용자 상호 작용 전용으로 유지될 수 있습니다.</p> |
| |
| |
| <h2 id="Basics">기본 정보</h2> |
| |
| <div class="sidebox-wrapper"> |
| <div class="sidebox"> |
| <h3>서비스와 스레드 중 어느 것을 사용해야 할까요?</h3> |
| <p>서비스는 그저 배경에서 실행될 수 있는 구성 요소일 뿐입니다. 이는 사용자가 |
| 애플리케이션과 상호 작용하지 않아도 관계 없이 해당됩니다. 따라서, 서비스를 생성하는 것은 꼭 그것이 필요할 때만으로 국한되어야 |
| 합니다.</p> |
| <p>기본 스레드 외부에서 작업을 수행해야 하지만 사용자가 애플리케이션과 상호 작용 중인 |
| 동안에만 수행하면 되는 경우라면, 서비스가 아니라 그 대신 새 스레드를 생성해야 합니다. 예를 들어 |
| 액티비티가 실행되는 중에만 음악을 재생하고자 하는 경우, |
| {@link android.app.Activity#onCreate onCreate()} 안에 스레드를 생성하고 이를 {@link |
| android.app.Activity#onStart onStart()}에서 실행하기 시작한 다음 {@link android.app.Activity#onStop |
| onStop()}에서 중단하면 됩니다. 또한, 기존의 {@link java.lang.Thread} 클래스 대신 |
| {@link android.os.AsyncTask} 또는 {@link android.os.HandlerThread}를 사용하는 방안도 고려하십시오. 스레드에 관한 자세한 정보는 <a href="{@docRoot}guide/components/processes-and-threads.html#Threads">프로세스 및 |
| 스레딩</a> 문서를 참조하십시오.</p> |
| <p>서비스를 사용하는 경우 기본적으로 애플리케이션의 기본 스레드에서 |
| 계속 실행되므로 서비스가 집약적이거나 차단적인 작업을 수행하는 경우 여전히 서비스 내에 |
| 새 스레드를 생성해야 한다는 점을 명심하십시오.</p> |
| </div> |
| </div> |
| |
| <p>서비스를 생성하려면 {@link android.app.Service}의 하위 클래스를 생성해야 합니다(아니면 이의 |
| 기존 하위 클래스 중 하나). 구현에서는 서비스 수명 주기의 주요 측면을 처리하는 콜백 메서드를 |
| 몇 가지 재정의해야 하며 서비스에 바인딩할 구성 요소에 대한 메커니즘을 |
| 제공해야 합니다(해당되는 경우). 재정의해야 하는 가장 중요한 콜백 메서드는 다음과 같습니다.</p> |
| |
| <dl> |
| <dt>{@link android.app.Service#onStartCommand onStartCommand()}</dt> |
| <dd>시스템이 이 메서드를 호출하는 것은 또 다른 구성 요소(예: 액티비티)가 서비스를 |
| 시작하도록 요청하는 경우입니다. 이때 {@link android.content.Context#startService |
| startService()}를 호출하는 방법을 씁니다. 이 메서드가 실행되면 서비스가 시작되고 배경에서 무기한으로 실행될 수 |
| 있습니다. 이것을 구성하면 서비스의 작업이 완료되었을 때 해당 서비스를 중단하는 것은 |
| 개발자 본인의 책임입니다. 이때 {@link android.app.Service#stopSelf stopSelf()} 또는 {@link |
| android.content.Context#stopService stopService()}를 호출하면 됩니다 (바인딩만 제공하고자 하는 경우, 이 메서드를 구현하지 |
| 않아도 됩니다).</dd> |
| <dt>{@link android.app.Service#onBind onBind()}</dt> |
| <dd>시스템이 이 메서드를 호출하는 것은 또 다른 구성 요소가 해당 서비스에 바인딩되고자 하는 경우 |
| (예를 들어 RPC를 수행하기 위해)입니다. 이때 {@link android.content.Context#bindService |
| bindService()}를 호출하는 방법을 씁니다. 이 메서드를 구현할 때에는 클라이언트가 서비스와 통신을 주고받기 위해 사용할 |
| 인터페이스를 제공해야 합니다. 이때 {@link android.os.IBinder}를 반환하면 됩니다. 이 메서드는 항상 |
| 구현해야 하지만, 바인딩을 허용하지 않고자 하면 null을 반환해야 합니다.</dd> |
| <dt>{@link android.app.Service#onCreate()}</dt> |
| <dd>시스템이 이 메서드를 호출하는 것은 서비스가 처음 생성되어 일회성 설정 |
| 절차를 수행하는 경우입니다({@link android.app.Service#onStartCommand onStartCommand()} 또는 |
| {@link android.app.Service#onBind onBind()}를 호출하기 전에). 서비스가 이미 실행 중인 경우, 이 메서드는 호출되지 |
| 않습니다.</dd> |
| <dt>{@link android.app.Service#onDestroy()}</dt> |
| <dd>시스템이 이 메서드를 호출하는 것은 해당 서비스를 더 이상 사용하지 않고 소멸시키는 경우입니다. |
| 서비스에 이것을 구현해야 스레드, 등록된 각종 수신기(listener, receiver) 등 |
| 모든 리소스를 정리할 수 있습니다. 이것이 서비스가 수신하는 마지막 호출입니다.</dd> |
| </dl> |
| |
| <p>한 구성 요소가 {@link |
| android.content.Context#startService startService()}를 호출하여 서비스를 시작하면({@link |
| android.app.Service#onStartCommand onStartCommand()}로의 호출을 초래함), 해당 서비스는 |
| 알아서 {@link android.app.Service#stopSelf()}로 스스로를 중단할 때까지 또는 |
| 또 다른 구성 요소가 {@link android.content.Context#stopService stopService()}를 호출하여 서비스를 중단시킬 때까지 실행 중인 상태로 유지됩니다.</p> |
| |
| <p>한 구성 요소가 |
| {@link android.content.Context#bindService bindService()}를 호출하여 서비스를 생성하는 경우(그리고 {@link |
| android.app.Service#onStartCommand onStartCommand()}를 호출하지 <em>않은</em> 경우), 해당 서비스는 |
| 해당 구성 요소가 바인딩되어 있는 경우에만 실행됩니다. 서비스가 모든 클라이언트로부터 바인딩 해제되면 시스템이 이를 |
| 소멸시킵니다.</p> |
| |
| <p>Android 시스템이 서비스를 강제 중단시키는 것은 메모리가 부족하여 사용자가 초점을 집중하고 있는 |
| 액티비티를 위해 시스템 리소스를 회복해야만 하는 경우로만 국한됩니다. 해당 서비스가 사용자의 주목을 |
| 끌고 있는 액티비티에 바인딩되어 있다면 중단될 가능성이 낮고, 서비스가 <a href="#Foreground">전경에서 실행</a>된다고 선언된 경우(나중에 자세히 논함), 거의 절대 중단되지 않습니다. |
| 그렇지 않으면, 서비스가 시작되었고 오랫동안 실행되는 경우 |
| 시간이 지나면서 시스템이 배경 작업 목록에서의 이 서비스의 위치를 점점 낮추고 |
| 서비스는 중단되기 매우 쉬워집니다. 서비스가 시작되었다면 이를 시스템에 의한 재시작을 정상적으로 |
| 처리하도록 디자인해야 합니다. 시스템이 서비스를 중단시키는 경우, 리소스를 다시 사용할 수 있게 되면 |
| 시스템이 가능한 한 빨리 이를 다시 시작합니다(다만 이것은 개발자가 {@link |
| android.app.Service#onStartCommand onStartCommand()}에서 반환하는 값에도 좌우됩니다. 이 내용은 나중에 논합니다). 시스템이 서비스를 |
| 소멸시킬 수 있는 경우에 대한 자세한 정보는 <a href="{@docRoot}guide/components/processes-and-threads.html">프로세스 및 스레딩</a> |
| 문서를 참조하십시오.</p> |
| |
| <p>다음 섹션에서는 각 유형의 서비스를 생성하는 방법과 다른 애플리케이션 구성 요소에서 |
| 이를 사용하는 방법을 배우게 됩니다.</p> |
| |
| |
| |
| <h3 id="Declaring">매니페스트에서 서비스 선언하기</h3> |
| |
| <p>액티비티(및 다른 구성 요소)와 마찬가지로, 서비스는 모두 애플리케이션의 매니페스트 |
| 파일에서 선언해야 합니다.</p> |
| |
| <p>서비스를 선언하려면 <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> 요소를 |
| <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> |
| 요소의 하위로 추가하면 됩니다. 예:</p> |
| |
| <pre> |
| <manifest ... > |
| ... |
| <application ... > |
| <service android:name=".ExampleService" /> |
| ... |
| </application> |
| </manifest> |
| </pre> |
| |
| <p>매니페스트에서 서비스를 선언하는 데 대한 자세한 정보는 <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> |
| 요소 참조를 확인하십시오.</p> |
| |
| <p><a href="{@docRoot}guide/topics/manifest/service-element.html">{@code <service>}</a> 요소에 포함시킬 수 있는 다른 속성도 있습니다. |
| 이를 포함시켜 서비스를 시작하는 데 필요한 권한과 서비스가 실행되어야 하는 프로세스 등의 |
| 속성을 정의할 수 있습니다. <a href="{@docRoot}guide/topics/manifest/service-element.html#nm">{@code android:name}</a> |
| 속성이 유일한 필수 속성입니다. 이것은 서비스의 클래스 이름을 나타냅니다. 일단 애플리케이션을 |
| 게시하고 나면 이 이름을 변경해서는 안 됩니다. 이름을 변경하면 |
| 서비스를 시작하거나 바인딩할 명시적 인텐트에 대한 종속성으로 인해 코드를 단절시킬 위험이 있기 때문입니다(블로그 게시물의 <a href="http://android-developers.blogspot.com/2011/06/things-that-cannot-change.html"> |
| 바꿀 수 없는 항목</a>을 참조하십시오). |
| |
| <p>앱의 보안을 보장하려면 <strong> |
| {@link android.app.Service}을 시작하거나 바인딩할 때 항상 명시적 인텐트를 사용하고</strong> 서비스에 대한 인텐트 필터는 선언하지 마십시오. 어느 |
| 서비스를 시작할지 어느 정도 모호성을 허용하는 것이 중요한 경우, 서비스에 대해 |
| 인텐트 필터를 제공하고 구성 요소 이름을 {@link |
| android.content.Intent}에서 배제할 수 있지만, 그러면 해당 인텐트에 대한 패키지를 {@link |
| android.content.Intent#setPackage setPackage()}로 설정하여 대상 서비스에 대해 충분한 명확화를 |
| 제공하도록 해야 합니다.</p> |
| |
| <p>이외에도 서비스를 본인의 앱에만 사용 가능하도록 보장할 수도 있습니다. |
| <a href="{@docRoot}guide/topics/manifest/service-element.html#exported">{@code android:exported}</a> |
| 속성을 포함시킨 뒤 이를 {@code "false"}로 설정하면 됩니다. 이렇게 하면 다른 앱이 여러분의 서비스를 시작하지 못하도록 효과적으로 방지해주며, |
| 이는 명시적 인텐트를 사용하는 경우에도 문제 없이 적용됩니다.</p> |
| |
| |
| |
| |
| <h2 id="CreatingStartedService">시작된 서비스 생성하기</h2> |
| |
| <p>시작된 서비스란 다른 구성 요소가 {@link |
| android.content.Context#startService startService()}를 호출하여 시작하고, 그 결과 서비스의 |
| {@link android.app.Service#onStartCommand onStartCommand()} 메서드를 호출하는 결과를 초래한 것을 말합니다.</p> |
| |
| <p>서비스가 시작되면 이를 시작한 구성 요소와 독립된 자신만의 |
| 수명 주기를 가지며 해당 서비스는 배경에서 무기한으로 실행될 수 있습니다. 이는 해당 서비스를 |
| 시작한 구성 요소가 소멸되었더라도 무관합니다. 따라서, 서비스는 작업이 완료되면 |
| {@link android.app.Service#stopSelf stopSelf()}를 호출하여 스스로 알아서 중단되는 것이 정상이며 아니면 다른 구성 요소가 |
| {@link android.content.Context#stopService stopService()}를 호출하여 중단시킬 수도 있습니다.</p> |
| |
| <p>애플리케이션 구성 요소(예: 액티비티)가 서비스를 시작하려면 {@link |
| android.content.Context#startService startService()}를 호출하고, {@link android.content.Intent}를 |
| 전달하면 됩니다. 이것은 서비스를 나타내고 서비스가 사용할 모든 데이터를 포함합니다. 서비스는 이 |
| {@link android.content.Intent}를 {@link android.app.Service#onStartCommand |
| onStartCommand()} 메서드에서 수신합니다.</p> |
| |
| <p>예를 들어 어느 액티비티가 온라인 데이터베이스에 데이터를 약간 저장해야 한다고 가정합니다. 액티비티가 |
| 동반자 서비스를 시작하여 저장할 데이터를 이에 전달할 수 있습니다. 이때 인텐트를 {@link |
| android.content.Context#startService startService()}에 전달하면 됩니다. 서비스는 이 인텐트를 {@link |
| android.app.Service#onStartCommand onStartCommand()}에서 수신하고 인터넷에 연결한 다음 데이터베이스 |
| 트랜잭션을 수행합니다. 작업을 완료하면, 해당 서비스는 알아서 스스로 중단되고 |
| 소멸됩니다.</p> |
| |
| <p class="caution"><strong>주의:</strong> 서비스는 기본적으로 자신이 선언된 애플리케이션의 같은 |
| 프로세스에서 실행되기도 하고 해당 애플리케이션의 기본 스레드에서 실행되기도 합니다. 따라서, 사용자가 |
| 같은 애플리케이션의 액티비티와 상호 작용하는 동안 서비스가 집약적이거나 차단적인 작업을 수행하는 경우, |
| 해당 서비스 때문에 액티비티 성능이 느려지게 됩니다. 애플리케이션 성능에 영향을 미치는 것을 방지하려면, |
| 서비스 내에서 새 스레드를 시작해야 합니다.</p> |
| |
| <p>기존에는 시작된 서비스를 생성하기 위해 확장할 수 있는 클래스가 두 개 있었습니다.</p> |
| <dl> |
| <dt>{@link android.app.Service}</dt> |
| <dd>이것이 모든 서비스의 기본 클래스입니다. 이 클래스를 확장하는 경우, 서비스의 모든 작업을 수행할 |
| 새 스레드를 만드는 것이 중요합니다. 서비스가 기본적으로 애플리케이션의 기본 스레드를 사용하기 |
| 때문인데, 이로 인해 애플리케이션이 실행 중인 모든 액티비티의 성능이 |
| 느려질 수 있기 때문입니다.</dd> |
| <dt>{@link android.app.IntentService}</dt> |
| <dd>이것은 {@link android.app.Service}의 하위 클래스로, 작업자 스레드를 |
| 사용하여 모든 시작 요청을 처리하되 한 번에 하나씩 처리합니다. 서비스가 여러 개의 요청을 |
| 동시에 처리하지 않아도 되는 경우 이것이 최선의 옵션입니다. 해야 할 일은 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()}를 구현하는 것뿐으로, 이것이 각 시작 요청에 대한 인텐트를 수신하여 |
| 개발자는 배경 작업을 수행할 수 있습니다.</dd> |
| </dl> |
| |
| <p>다음 섹션에서는 이와 같은 클래스 중 하나를 사용하여 서비스를 구현하는 방법을 |
| 설명합니다.</p> |
| |
| |
| <h3 id="ExtendingIntentService">IntentService 클래스 확장하기</h3> |
| |
| <p>대부분의 시작된 서비스는 여러 개의 요청을 동시에 처리하지 않아도 되기 때문에 |
| (이는 사실 위험한 다중 스레딩 시나리오일 수 있습니다), 서비스를 구현할 때에는 |
| {@link android.app.IntentService} 클래스를 사용하는 것이 최선의 방안일 것입니다.</p> |
| |
| <p>{@link android.app.IntentService}는 다음과 같은 작업을 수행합니다.</p> |
| |
| <ul> |
| <li>애플리케이션의 기본 스레드와는 별도로 {@link |
| android.app.Service#onStartCommand onStartCommand()}에 전달된 모든 인텐트를 실행하는 기본 작업자 스레드를 |
| 생성합니다.</li> |
| <li>한 번에 인텐트를 하나씩 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()} 구현에 전달하는 작업 대기열을 생성하므로 다중 스레딩에 대해 염려할 필요가 |
| 전혀 없습니다.</li> |
| <li>시작 요청이 모두 처리된 후 서비스를 중단하므로 개발자가 |
| {@link android.app.Service#stopSelf}를 호출할 필요가 전혀 없습니다.</li> |
| <li>{@link android.app.IntentService#onBind onBind()}의 기본 구현을 제공하여 null을 |
| 반환하도록 합니다.</li> |
| <li>{@link android.app.IntentService#onStartCommand |
| onStartCommand()}의 기본 구현을 제공하여 인텐트를 작업 대기열에 보내고, 다음으로 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()} 구현에 보내도록 합니다.</li> |
| </ul> |
| |
| <p>이 모든 것은 결론적으로 개발자가 직접 할 일은 클라이언트가 제공한 작업을 수행할 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()}를 구현하는 것뿐이라는 사실로 |
| 이어집니다. (다만, 서비스에 대해 작은 생성자를 제공해야 하기도 합니다.)</p> |
| |
| <p>다음은 {@link android.app.IntentService}의 구현을 예시로 나타낸 것입니다.</p> |
| |
| <pre> |
| public class HelloIntentService extends IntentService { |
| |
| /** |
| * A constructor is required, and must call the super {@link android.app.IntentService#IntentService} |
| * constructor with a name for the worker thread. |
| */ |
| public HelloIntentService() { |
| super("HelloIntentService"); |
| } |
| |
| /** |
| * The IntentService calls this method from the default worker thread with |
| * the intent that started the service. When this method returns, IntentService |
| * stops the service, as appropriate. |
| */ |
| @Override |
| protected void onHandleIntent(Intent intent) { |
| // Normally we would do some work here, like download a file. |
| // For our sample, we just sleep for 5 seconds. |
| long endTime = System.currentTimeMillis() + 5*1000; |
| while (System.currentTimeMillis() < endTime) { |
| synchronized (this) { |
| try { |
| wait(endTime - System.currentTimeMillis()); |
| } catch (Exception e) { |
| } |
| } |
| } |
| } |
| } |
| </pre> |
| |
| <p>필요한 것은 이게 전부입니다. 생성자 하나와 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()} 구현뿐이죠.</p> |
| |
| <p>다른 콜백 메서드도 재정의하기로 결정하는 경우-예를 들어 {@link |
| android.app.IntentService#onCreate onCreate()}, {@link |
| android.app.IntentService#onStartCommand onStartCommand()} 또는 {@link |
| android.app.IntentService#onDestroy onDestroy()}-슈퍼 구현을 꼭 호출해야 합니다. |
| 그래야 {@link android.app.IntentService}가 작업자 스레드의 수명을 적절하게 처리할 수 있습니다.</p> |
| |
| <p>예를 들어 {@link android.app.IntentService#onStartCommand onStartCommand()}는 반드시 |
| 기본 구현을 반환해야 합니다(이로써 인텐트가 {@link |
| android.app.IntentService#onHandleIntent onHandleIntent()}로 전달되는 것입니다).</p> |
| |
| <pre> |
| @Override |
| public int onStartCommand(Intent intent, int flags, int startId) { |
| Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); |
| return super.onStartCommand(intent,flags,startId); |
| } |
| </pre> |
| |
| <p>{@link android.app.IntentService#onHandleIntent onHandleIntent()} 외에 슈퍼 클래스를 |
| 호출하지 않아도 되는 유일한 메서드는 {@link android.app.IntentService#onBind |
| onBind()}입니다(다만 이를 구현하는 것은 서비스가 바인딩을 허용할 때에만 필요합니다).</p> |
| |
| <p>다음 섹션에서는 기본 {@link android.app.Service} |
| 클래스를 확장할 때 같은 종류의 서비스를 구현하는 방법을 배우게 됩니다. 이때에는 코드가 훨씬 많이 필요하지만, |
| 동시 시작 요청을 처리해야 하는 경우 이것이 적절할 수 있습니다.</p> |
| |
| |
| <h3 id="ExtendingService">서비스 클래스 확장하기</h3> |
| |
| <p>이전 섹션에서 본 것과 같이 {@link android.app.IntentService}를 사용하면 |
| 시작된 서비스 구현이 매우 단순해집니다. 하지만 서비스가 다중 스레딩을 |
| 수행해야 하는 경우(작업 대기열을 통해 시작 요청을 처리하는 대신), 그때는 |
| {@link android.app.Service} 클래스를 확장하여 각 인텐트를 처리하게 할 수 있습니다.</p> |
| |
| <p>비교를 위해 다음 예시의 코드를 보겠습니다. 이는 {@link |
| android.app.Service} 클래스의 구현으로, 위의 예시에서 {@link |
| android.app.IntentService}를 사용하여 수행한 것과 똑같은 작업을 수행합니다. 바꿔 말하면 각 시작 요청에 대해 |
| 작업자 스레드를 사용하여 작업을 수행하고 한 번에 요청을 하나씩만 처리한다는 뜻입니다.</p> |
| |
| <pre> |
| public class HelloService extends Service { |
| private Looper mServiceLooper; |
| private ServiceHandler mServiceHandler; |
| |
| // Handler that receives messages from the thread |
| private final class ServiceHandler extends Handler { |
| public ServiceHandler(Looper looper) { |
| super(looper); |
| } |
| @Override |
| public void handleMessage(Message msg) { |
| // Normally we would do some work here, like download a file. |
| // For our sample, we just sleep for 5 seconds. |
| long endTime = System.currentTimeMillis() + 5*1000; |
| while (System.currentTimeMillis() < endTime) { |
| synchronized (this) { |
| try { |
| wait(endTime - System.currentTimeMillis()); |
| } catch (Exception e) { |
| } |
| } |
| } |
| // Stop the service using the startId, so that we don't stop |
| // the service in the middle of handling another job |
| stopSelf(msg.arg1); |
| } |
| } |
| |
| @Override |
| public void onCreate() { |
| // Start up the thread running the service. Note that we create a |
| // separate thread because the service normally runs in the process's |
| // main thread, which we don't want to block. We also make it |
| // background priority so CPU-intensive work will not disrupt our UI. |
| HandlerThread thread = new HandlerThread("ServiceStartArguments", |
| Process.THREAD_PRIORITY_BACKGROUND); |
| thread.start(); |
| |
| // Get the HandlerThread's Looper and use it for our Handler |
| mServiceLooper = thread.getLooper(); |
| mServiceHandler = new ServiceHandler(mServiceLooper); |
| } |
| |
| @Override |
| public int onStartCommand(Intent intent, int flags, int startId) { |
| Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); |
| |
| // For each start request, send a message to start a job and deliver the |
| // start ID so we know which request we're stopping when we finish the job |
| Message msg = mServiceHandler.obtainMessage(); |
| msg.arg1 = startId; |
| mServiceHandler.sendMessage(msg); |
| |
| // If we get killed, after returning from here, restart |
| return START_STICKY; |
| } |
| |
| @Override |
| public IBinder onBind(Intent intent) { |
| // We don't provide binding, so return null |
| return null; |
| } |
| |
| @Override |
| public void onDestroy() { |
| Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); |
| } |
| } |
| </pre> |
| |
| <p>보시다시피 {@link android.app.IntentService}를 사용할 때보다 훨씬 손이 많이 갑니다.</p> |
| |
| <p>그러나, 각 호출을 {@link android.app.Service#onStartCommand |
| onStartCommand()}로 직접 처리할 수 있기 때문에 여러 개의 요청을 동시에 수행할 수 있습니다. 이 예시는 그것을 |
| 보여주는 것은 아니지만, 그런 작업을 원하는 경우 각 요청에 대해 새 스레드를 |
| 하나씩 생성한 다음 곧바로 실행하면 됩니다(이전 요청이 끝날 때까지 기다리는 대신).</p> |
| |
| <p>{@link android.app.Service#onStartCommand onStartCommand()} 메서드가 반드시 |
| 정수를 반환해야 한다는 사실을 유의하십시오. 정수는 시스템이 서비스를 중단시킨 경우 시스템이 해당 서비스를 |
| 계속하는 방법에 대해 설명하는 값입니다(위에서 논한 바와 같이 {@link |
| android.app.IntentService}의 기본 구현이 이것을 개발자 대신 처리해줍니다. 개발자가 이를 수정할 수도 있습니다). |
| {@link android.app.Service#onStartCommand onStartCommand()}로부터의 반환 값은 반드시 |
| 다음 상수 중 하나여야 합니다.</p> |
| |
| <dl> |
| <dt>{@link android.app.Service#START_NOT_STICKY}</dt> |
| <dd>시스템이 서비스를 {@link android.app.Service#onStartCommand |
| onStartCommand()} 반환 후에 중단시키면 서비스를 재생성하면 <em>안 됩니다.</em> 다만 전달할 |
| 보류 인텐트가 있는 경우는 예외입니다. 이것은 서비스가 불필요하게 실행되는 일을 피할 수 있는 가장 안전한 옵션이며, |
| 애플리케이션이 완료되지 않은 모든 작업을 단순히 재시작할 수 있을 때 좋습니다.</dd> |
| <dt>{@link android.app.Service#START_STICKY}</dt> |
| <dd>시스템이 서비스를 {@link android.app.Service#onStartCommand |
| onStartCommand()} 반환 후에 중단시키는 경우, 서비스를 재생성하고 {@link |
| android.app.Service#onStartCommand onStartCommand()}를 호출하되 마지막 인텐트를 다시 전달하지는 <em>마십시오.</em> |
| 그 대신, 시스템이 null 인텐트로 {@link android.app.Service#onStartCommand onStartCommand()}를 |
| 호출합니다. 다만 서비스를 시작할 보류 인텐트가 있는 경우만은 예외이며, 이럴 때에는 |
| 그러한 인텐트를 전달합니다. 이것은 명령을 실행하지는 않지만 무기한으로 실행 중이며 작업을 기다리고 있는 |
| 미디어 플레이어(또는 그와 비슷한 서비스)에 적합합니다.</dd> |
| <dt>{@link android.app.Service#START_REDELIVER_INTENT}</dt> |
| <dd>시스템이 서비스를 {@link android.app.Service#onStartCommand |
| onStartCommand()} 반환 후에 중단시키는 경우, 서비스를 재생성하고 서비스에 전달된 마지막 인텐트로 {@link |
| android.app.Service#onStartCommand onStartCommand()}를 |
| 호출하십시오. 모든 보류 인텐트가 차례로 전달됩니다. 이것은 즉시 재개되어야 하는 작업을 |
| 능동적으로 수행 중인 서비스(예를 들어 파일 다운로드 등)에 적합합니다.</dd> |
| </dl> |
| <p>이러한 반환 값에 대한 자세한 내용은 각 상수에 대해 링크로 연결된 참조 문서를 |
| 확인하십시오.</p> |
| |
| |
| |
| <h3 id="StartingAService">서비스 시작</h3> |
| |
| <p>액티비티나 다른 구성 요소에서 서비스를 시작하려면 |
| {@link android.content.Intent}를(시작할 서비스를 나타냄) {@link |
| android.content.Context#startService startService()}에 전달하면 됩니다. Android 시스템이 서비스의 {@link |
| android.app.Service#onStartCommand onStartCommand()} 메서드를 호출하여 여기에 {@link |
| android.content.Intent}를 전달합니다. ({@link android.app.Service#onStartCommand |
| onStartCommand()}를 직접 호출하면 절대로 안 됩니다.)</p> |
| |
| <p>예를 들어 이전 섹션의 예시 서비스({@code |
| HelloService})를 액티비티가 시작하려면 {@link android.content.Context#startService |
| startService()}로 명시적 인텐트를 사용하면 됩니다.</p> |
| |
| <pre> |
| Intent intent = new Intent(this, HelloService.class); |
| startService(intent); |
| </pre> |
| |
| <p>{@link android.content.Context#startService startService()} 메서드가 즉시 반환되며 |
| Android 시스템이 서비스의 {@link android.app.Service#onStartCommand |
| onStartCommand()} 메서드를 호출합니다. 서비스가 이미 실행 중이지 않은 경우, 시스템은 우선 {@link |
| android.app.Service#onCreate onCreate()}를 호출하고, 다음으로 {@link android.app.Service#onStartCommand |
| onStartCommand()}를 호출합니다.</p> |
| |
| <p>서비스가 바인딩도 제공하지 않는 경우, {@link |
| android.content.Context#startService startService()}와 함께 전달된 인텐트가 애플리케이션 구성 요소와 서비스 사이의 |
| 유일한 통신 방법입니다. 그러나 서비스가 결과를 돌려보내기를 원하는 경우, 서비스를 시작한 |
| 클라이언트가 브로드캐스트를 위해 {@link android.app.PendingIntent}를 |
| 만들 수 있고({@link android.app.PendingIntent#getBroadcast getBroadcast()} 사용) 이를 서비스를 시작한 |
| {@link android.content.Intent} 내의 서비스에 전달할 수 있습니다. 그러면 서비스가 |
| 이 브로드캐스트를 사용하여 결과를 전달할 수 있게 됩니다.</p> |
| |
| <p>서비스를 시작하기 위한 여러 개의 요청은 서비스의 |
| {@link android.app.Service#onStartCommand onStartCommand()}로의 상응하는 여러 개의 호출이라는 결과를 낳습니다. 하지만, 서비스를 중단하려면 |
| 이를 중단하라는 요청 하나({@link android.app.Service#stopSelf stopSelf()} 또는 {@link |
| android.content.Context#stopService stopService()} 사용)만 있으면 됩니다.</p> |
| |
| |
| <h3 id="Stopping">서비스 중단</h3> |
| |
| <p>시작된 서비스는 자신만의 수명 주기를 직접 관리해야 합니다. 다시 말해, 시스템이 |
| 서비스를 중단하거나 소멸시키지 않는다는 뜻입니다. 다만 시스템 메모리를 회복해야 하고 서비스가 |
| {@link android.app.Service#onStartCommand onStartCommand()} 반환 후에도 계속 실행되는 경우는 예외입니다. 따라서, |
| 서비스는 {@link android.app.Service#stopSelf stopSelf()}를 호출하여 스스로 중단시켜야 하고, 아니면 |
| 다른 구성 요소가 {@link android.content.Context#stopService stopService()}를 호출하여 이를 중단시킬 수 있습니다.</p> |
| |
| <p>일단 {@link android.app.Service#stopSelf stopSelf()} 또는 {@link |
| android.content.Context#stopService stopService()}로 중단하기를 요청하고 나면 시스템이 서비스를 가능한 한 빨리 |
| 소멸시킵니다.</p> |
| |
| <p>그러나, 서비스가 {@link |
| android.app.Service#onStartCommand onStartCommand()}로의 요청을 동시에 여러 개 처리하기를 바라는 경우라면 시작 요청 처리를 완료한 뒤에도 |
| 서비스를 중단하면 안 됩니다. 그 이후 새 시작 요청을 받았을 수 있기 |
| 때문입니다(첫 요청 종료 시에 중단하면 두 번째 요청을 종료시킵니다). 이 문제를 |
| 피하려면, {@link android.app.Service#stopSelf(int)}를 사용하여 서비스를 |
| 중단시키라는 개발자의 요청이 항상 최신 시작 요청에 기반하도록 해야 합니다. 다시 말해, {@link |
| android.app.Service#stopSelf(int)}를 호출할 때면 시작 요청의 ID({@link android.app.Service#onStartCommand onStartCommand()}에 전달된 |
| <code>startId</code>)를 전달하게 됩니다. 여기에 중단 요청이 |
| 부합됩니다. 그런 다음 개발자가 {@link |
| android.app.Service#stopSelf(int)}를 호출할 수 있기 전에 서비스가 새 시작 요청을 받은 경우, ID가 일치하지 않게 되고 서비스는 중단되지 않습니다.</p> |
| |
| <p class="caution"><strong>주의:</strong> 서비스가 작업을 완료한 다음 애플리케이션이 |
| 소속 서비스를 중단할 수 있어야 한다는 점이 중요합니다. 그래야 시스템 리소스 낭비를 피하고 배터리 전력 소모를 줄일 수 있습니다. 필요한 경우 |
| 다른 구성 요소도 서비스를 중단시킬 수 있습니다. {@link |
| android.content.Context#stopService stopService()}를 호출하면 됩니다. 서비스에 대해 바인딩을 활성화하더라도, |
| 서비스가 {@link |
| android.app.Service#onStartCommand onStartCommand()}로의 호출을 한 번이라도 받았으면 항상 서비스를 직접 중단시켜야 합니다.</p> |
| |
| <p>서비스의 수명 주기에 대한 자세한 정보는 아래에 있는 <a href="#Lifecycle">서비스 수명 주기 관리</a>에 관한 섹션을 참고하세요.</p> |
| |
| |
| |
| <h2 id="CreatingBoundService">바인딩된 서비스 생성</h2> |
| |
| <p>바인딩된 서비스는 애플리케이션 구성 요소가 자신에게 바인딩될 수 있도록 허용하는 서비스로, 이때 {@link |
| android.content.Context#bindService bindService()}를 호출하여 오래 지속되는 연결을 생성합니다 |
| (또한 보통은 구성 요소가 {@link |
| android.content.Context#startService startService()}를 호출하여 서비스를 <em>시작</em>하는 것을 허용하지 않습니다).</p> |
| |
| <p>액티비티와 애플리케이션의 다른 구성 요소에서 서비스와 상호 작용하기를 원하는 경우 |
| 바인딩된 서비스를 생성해야 합니다. 아니면 애플리케이션의 기능 몇 가지를 프로세스 간 통신(IPC)을 통해 |
| 다른 애플리케이션에 노출하고자 하는 경우에도 좋습니다.</p> |
| |
| <p>바인딩된 서비스를 생성하려면 {@link |
| android.app.Service#onBind onBind()} 콜백 메서드를 구현하여 서비스와의 통신을 위한 인터페이스를 정의하는 |
| {@link android.os.IBinder}를 반환하도록 해야 합니다. 그러면 다른 애플리케이션 구성 요소가 |
| {@link android.content.Context#bindService bindService()}를 호출하여 해당 인터페이스를 검색하고, 서비스에 있는 메서드를 |
| 호출하기 시작할 수 있습니다. 서비스는 자신에게 바인딩된 애플리케이션 구성 요소에게 도움이 되기 위해서만 |
| 존재하는 것이므로, 서비스에 바인딩된 구성 요소가 없으면 시스템이 이를 소멸시킵니다(바인딩된 서비스는 시작된 서비스처럼 |
| {@link android.app.Service#onStartCommand onStartCommand()}를 통해 |
| 중단시키지 <em>않아도</em> 됩니다).</p> |
| |
| <p>바인딩된 서비스를 생성하려면 가장 먼저 해야 할 일은 클라이언트가 서비스와 |
| 통신할 수 있는 방법을 나타내는 인터페이스를 정의하는 것입니다. 서비스와 클라이언트 사이에서 쓰이는 이 인터페이스는 |
| 반드시 {@link android.os.IBinder}의 구현이어야 하며 이를 |
| 서비스가 {@link android.app.Service#onBind |
| onBind()} 콜백 메서드에서 반환해야 합니다. 클라이언트가 {@link android.os.IBinder}를 수신하면 해당 인터페이스를 통해 서비스와 |
| 상호 작용을 시작할 수 있습니다.</p> |
| |
| <p>여러 클라이언트가 서비스에 한꺼번에 바인딩될 수 있습니다. 클라이언트가 서비스와의 상호 작용을 완료하면 이는 |
| {@link android.content.Context#unbindService unbindService()}를 호출하여 바인딩을 해제합니다. 서비스에 |
| 바인딩된 클라이언트가 하나도 없으면 시스템이 해당 서비스를 소멸시킵니다.</p> |
| |
| <p>바인딩된 서비스를 구현하는 데에는 여러 가지 방법이 있으며 그러한 구현은 시작된 서비스보다 |
| 훨씬 복잡합니다. 따라서 바인딩된 서비스 논의는 |
| <a href="{@docRoot}guide/components/bound-services.html">바인딩된 서비스</a>에 관한 별도의 문서에서 다룹니다.</p> |
| |
| |
| |
| <h2 id="Notifications">사용자에게 알림 전송</h2> |
| |
| <p>서비스는 일단 실행되고 나면 사용자에게 <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">알림 메시지</a> 또는 <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">상태 표시줄 알림</a> 등을 사용해 이벤트를 알릴 수 있습니다.</p> |
| |
| <p>알림 메시지란 현재 창의 표면에 잠시 나타났다가 사라지는 메시지이고, |
| 상태 표시줄 알림은 상태 표시줄에 메시지가 담긴 아이콘을 제공하여 사용자가 이를 선택하여 |
| 조치를 취할 수 있게 하는 것입니다(예: 액티비티 시작).</p> |
| |
| <p>보통, 일종의 배경 작업이 완료되었고 |
| (예: 파일 다운로드 완료) 이제 사용자가 그에 대해 조치를 취할 수 있는 경우 상태 표시줄 알림이 |
| 최선의 기법입니다. 사용자가 확장된 보기에서 알림을 선택하면, |
| 해당 알림이 액티비티를 시작할 수 있습니다(예: 다운로드한 파일 보기).</p> |
| |
| <p>자세한 정보는 <a href="{@docRoot}guide/topics/ui/notifiers/toasts.html">알림 메시지</a> 또는 <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">상태 표시줄 알림</a> |
| 개발자 가이드를 참조하십시오.</p> |
| |
| |
| |
| <h2 id="Foreground">전경에서 서비스 실행하기</h2> |
| |
| <p>전경 서비스는 사용자가 능동적으로 인식하고 있으므로 메모리 부족 시에도 |
| 시스템이 중단할 후보로 고려되지 않는 서비스를 말합니다. 전경 |
| 서비스는 상태 표시줄에 대한 알림을 제공해야 합니다. 이것은 |
| "진행 중" 제목 아래에 배치되며, 이는 곧 해당 알림은 서비스가 중단되었거나 |
| 전경에서 제거되지 않은 이상 무시할 수 없다는 뜻입니다.</p> |
| |
| <p>예를 들어 서비스에서 음악을 재생하는 음악 플레이어는 전경에서 |
| 실행되도록 설정해야 합니다. 사용자가 이것의 작동을 분명히 인식하고 있기 |
| 때문입니다. 상태 표시줄에 있는 알림은 현재 노래를 나타내고 |
| 사용자로 하여금 음악 플레이어와 상호 작용할 액티비티를 시작하게 해줄 수도 있습니다.</p> |
| |
| <p>서비스가 전경에서 실행되도록 요청하려면 {@link |
| android.app.Service#startForeground startForeground()}를 호출하면 됩니다. 이 메서드는 두 개의 매개변수를 취합니다. |
| 그 중 하나는 해당 알림을 고유하게 식별하는 정수이고 다른 하나는 상태 표시줄에 해당되는 {@link |
| android.app.Notification}입니다. 예:</p> |
| |
| <pre> |
| Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text), |
| System.currentTimeMillis()); |
| Intent notificationIntent = new Intent(this, ExampleActivity.class); |
| PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); |
| notification.setLatestEventInfo(this, getText(R.string.notification_title), |
| getText(R.string.notification_message), pendingIntent); |
| startForeground(ONGOING_NOTIFICATION_ID, notification); |
| </pre> |
| |
| <p class="caution"><strong>주의:</strong> {@link |
| android.app.Service#startForeground startForeground()}에 부여하는 정수 ID가 0이면 안 됩니다.</p> |
| |
| |
| <p>서비스를 전경에서 제거하려면 {@link |
| android.app.Service#stopForeground stopForeground()}를 호출하면 됩니다. 이 메서드는 부울 값을 취하며, 이것이 |
| 상태 표시줄 알림도 제거할지 여부를 나타냅니다. 이 메서드는 서비스를 중단시키지 <em>않습니다</em>. |
| 그러나, 서비스가 전경에서 실행 중인 동안 서비스를 중단시키면 |
| 알림도 마찬가지로 제거됩니다.</p> |
| |
| <p>알림에 대한 자세한 정보는 <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html">상태 표시줄 |
| 알림 생성</a>을 참조하십시오.</p> |
| |
| |
| |
| <h2 id="Lifecycle">서비스 수명 주기 관리</h2> |
| |
| <p>서비스의 수명 주기는 액티비티의 수명 주기보다 훨씬 간단합니다. 하지만, 서비스를 생성하고 |
| 소멸시키는 방법에 특히 주의를 기울여야 한다는 면에서 중요도는 이쪽이 더 높습니다. 서비스는 사용자가 모르는 채로 |
| 배경에서 실행될 수 있기 때문입니다.</p> |
| |
| <p>서비스 수명 주기—생성되었을 때부터 소멸될 때까지—는 두 가지 서로 다른 경로를 |
| 따를 수 있습니다.</p> |
| |
| <ul> |
| <li>시작된 서비스 |
| <p>서비스는 또 다른 구성 요소가 {@link |
| android.content.Context#startService startService()}를 호출하면 생성됩니다. 그러면 서비스가 무기한으로 실행될 수 있으며 |
| 스스로 알아서 중단되어야 합니다. 이때 {@link |
| android.app.Service#stopSelf() stopSelf()}를 호출하는 방법을 씁니다. 또 다른 구성 요소도 서비스를 중단시킬 수 |
| 있습니다. {@link android.content.Context#stopService |
| stopService()}를 호출하면 됩니다. 서비스가 중단되면 시스템이 이를 소멸시킵니다.</p></li> |
| |
| <li>바인딩된 서비스 |
| <p>서비스는 또 다른 구성 요소(클라이언트)가 {@link |
| android.content.Context#bindService bindService()}를 호출하면 생성됩니다. 그러면 클라이언트가 |
| {@link android.os.IBinder} 인터페이스를 통해 서비스와 통신을 주고받을 수 있습니다. 클라이언트가 연결을 종료하려면 |
| {@link android.content.Context#unbindService unbindService()}를 호출하면 됩니다. 여러 클라이언트가 같은 서비스에 |
| 바인딩될 수 있으며, 이 모두가 바인딩을 해제하면 시스템이 해당 서비스를 소멸시킵니다 (서비스가 스스로를 중단시키지 |
| <em>않아도</em> 됩니다).</p></li> |
| </ul> |
| |
| <p>이와 같은 두 가지 경로는 완전히 별개의 것은 아닙니다. 다시 말해, 이미 |
| {@link android.content.Context#startService startService()}로 시작된 서비스에 바인딩할 수도 있다는 뜻입니다. 예를 |
| 들어, 배경 음악 서비스를 시작하려면 {@link android.content.Context#startService |
| startService()}를 호출하되 재생할 음악을 식별하는 {@link android.content.Intent}를 사용하면 됩니다. 나중에, |
| 아마도 사용자가 플레이어에 좀 더 많은 통제권을 발휘하고자 하거나 |
| 현재 노래에 대한 정보를 얻고자 할 때, 액티비티가 서비스에 바인딩될 수 있습니다. {@link |
| android.content.Context#bindService bindService()}를 사용하면 됩니다. 이런 경우에는 {@link |
| android.content.Context#stopService stopService()} 또는 {@link android.app.Service#stopSelf |
| stopSelf()}도 클라이언트가 모두 바인딩 해제될 때까지 실제로 서비스를 중단시키지 않습니다. </p> |
| |
| |
| <h3 id="LifecycleCallbacks">수명 주기 콜백 구현하기</h3> |
| |
| <p>액티비티와 마찬가지로 서비스에도 수명 주기 콜백 메서드가 있어 이를 구현하면 서비스의 |
| 상태 변경 내용을 모니터링할 수 있고 적절한 시기에 작업을 수행할 수 있습니다. 다음의 골격 |
| 서비스는 각 수명 주기 메서드를 설명한 것입니다.</p> |
| |
| <pre> |
| public class ExampleService extends Service { |
| int mStartMode; // indicates how to behave if the service is killed |
| IBinder mBinder; // interface for clients that bind |
| boolean mAllowRebind; // indicates whether onRebind should be used |
| |
| @Override |
| public void {@link android.app.Service#onCreate onCreate}() { |
| // The service is being created |
| } |
| @Override |
| public int {@link android.app.Service#onStartCommand onStartCommand}(Intent intent, int flags, int startId) { |
| // The service is starting, due to a call to {@link android.content.Context#startService startService()} |
| return <em>mStartMode</em>; |
| } |
| @Override |
| public IBinder {@link android.app.Service#onBind onBind}(Intent intent) { |
| // A client is binding to the service with {@link android.content.Context#bindService bindService()} |
| return <em>mBinder</em>; |
| } |
| @Override |
| public boolean {@link android.app.Service#onUnbind onUnbind}(Intent intent) { |
| // All clients have unbound with {@link android.content.Context#unbindService unbindService()} |
| return <em>mAllowRebind</em>; |
| } |
| @Override |
| public void {@link android.app.Service#onRebind onRebind}(Intent intent) { |
| // A client is binding to the service with {@link android.content.Context#bindService bindService()}, |
| // after onUnbind() has already been called |
| } |
| @Override |
| public void {@link android.app.Service#onDestroy onDestroy}() { |
| // The service is no longer used and is being destroyed |
| } |
| } |
| </pre> |
| |
| <p class="note"><strong>참고:</strong> 액티비티 수명 주기 콜백 메서드와는 달리 이와 같은 콜백 메서드를 구현하는 데에는 |
| 슈퍼클래스 구현을 호출하지 <em>않아도</em> 됩니다.</p> |
| |
| <img src="{@docRoot}images/service_lifecycle.png" alt="" /> |
| <p class="img-caption"><strong>그림 2.</strong> 서비스 수명 주기입니다. 왼쪽의 다이어그램은 |
| 서비스가 {@link android.content.Context#startService |
| startService()}로 생성된 경우의 수명 주기를 나타내며 오른쪽의 다이어그램은 서비스가 |
| {@link android.content.Context#bindService bindService()}로 생성된 경우의 수명 주기를 나타낸 것입니다.</p> |
| |
| <p>이와 같은 메서드를 구현함으로써, 서비스 수명 주기의 두 가지 중첩된 루프를 모니터링할 수 있습니다. </p> |
| |
| <ul> |
| <li>서비스의 <strong>수명 주기 전체</strong>는 {@link |
| android.app.Service#onCreate onCreate()}가 호출된 시점과 {@link |
| android.app.Service#onDestroy}가 반환된 시점 사이에 일어납니다. 액티비티와 마찬가지로 서비스는 자신의 초기 설정을 |
| {@link android.app.Service#onCreate onCreate()}에서 수행하며 남은 리소스를 모두 {@link |
| android.app.Service#onDestroy onDestroy()}에 릴리스합니다. 예를 들어 |
| 음악 재생 서비스의 경우 음악이 재생될 스레드를 {@link |
| android.app.Service#onCreate onCreate()}로 생성하고, 그럼 다음 해당 스레드를 중단할 때에는 {@link |
| android.app.Service#onDestroy onDestroy()}에서 할 수도 있습니다. |
| |
| <p>{@link android.app.Service#onCreate onCreate()}와 {@link android.app.Service#onDestroy |
| onDestroy()} 메서드는 모든 서비스에 대해 호출됩니다. 이는 서비스가 |
| {@link android.content.Context#startService startService()}로 생성되었든 {@link |
| android.content.Context#bindService bindService()}로 생성되었든 관계 없이 적용됩니다.</p></li> |
| |
| <li>서비스의 <strong>활성 수명 주기</strong>는 {@link |
| android.app.Service#onStartCommand onStartCommand()} 또는 {@link android.app.Service#onBind onBind()}로의 호출과 함께 시작됩니다. |
| 각 메서드에 {@link |
| android.content.Intent}가 전달되는데 이것은 각각 {@link android.content.Context#startService |
| startService()} 또는 {@link android.content.Context#bindService bindService()} 중 하나에 전달된 것입니다. |
| <p>서비스가 시작되면 수명 주기 전체가 종료되는 것과 동시에 활성 수명 주기도 종료됩니다 |
| (서비스는 {@link android.app.Service#onStartCommand |
| onStartCommand()}가 반환된 뒤에도 여전히 활성 상태입니다). 서비스가 바인딩된 경우, 활성 수명 주기는 {@link |
| android.app.Service#onUnbind onUnbind()}가 반환되면 종료됩니다.</p> |
| </li> |
| </ul> |
| |
| <p class="note"><strong>참고:</strong> 시작된 서비스를 중단하려면 |
| {@link android.app.Service#stopSelf stopSelf()} 또는 {@link |
| android.content.Context#stopService stopService()}를 호출하면 되지만, 서비스에 대한 상응하는 콜백은 |
| 없습니다(즉 {@code onStop()} 콜백이 없습니다). 그러므로, 서비스가 클라이언트에 바인딩되어 있지 않은 한 |
| 시스템은 서비스가 중단되면 이를 소멸시킵니다. 수신되는 콜백은 {@link |
| android.app.Service#onDestroy onDestroy()}가 유일합니다.</p> |
| |
| <p>그림 2는 서비스에 대한 일반적인 콜백 메서드를 나타낸 것입니다. 이 그림에서는 |
| {@link android.content.Context#startService startService()}로 생성된 서비스와 |
| {@link android.content.Context#bindService bindService()}로 생성된 서비스를 |
| 구분하고 있지만, 어떤 식으로 시작되었든 모든 서비스는 클라이언트가 자신에 바인딩되도록 허용할 수 있다는 점을 명심하십시오. |
| 말하자면, {@link android.app.Service#onStartCommand |
| onStartCommand()}로 처음 시작된 서비스(클라이언트가 {@link android.content.Context#startService startService()}를 호출해서)라고 해도 |
| 여전히 {@link android.app.Service#onBind onBind()}로의 호출을 받을 수 있습니다(클라이언트가 |
| {@link android.content.Context#bindService bindService()}를 호출하는 경우).</p> |
| |
| <p>바인딩을 제공하는 서비스 생성에 대한 자세한 내용은 <a href="{@docRoot}guide/components/bound-services.html">바인딩된 서비스</a> 문서를 참조하십시오. 이 안에는 {@link android.app.Service#onRebind onRebind()} |
| 콜백 메서드에 대한 자세한 정보가 <a href="{@docRoot}guide/components/bound-services.html#Lifecycle">바인딩된 서비스의 |
| 수명 주기 관리</a>에 관한 섹션에 |
| 담겨 있습니다.</p> |
| |
| |
| <!-- |
| <h2>Beginner's Path</h2> |
| |
| <p>To learn how to query data from the system or other applications (such as contacts or media |
| stored on the device), continue with the <b><a |
| href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a></b> |
| document.</p> |
| --> |