Android 서비스 만들기

이 가이드에서는 활성 사용자 인터페이스 없이 작업을 수행할 수 있는 Android 구성 요소인 Xamarin.Android 서비스에 대해 설명합니다. 서비스는 시간 소모 계산, 파일 다운로드, 음악 재생 등과 같이 백그라운드에서 수행되는 작업에 매우 일반적으로 사용됩니다. 서비스에 적합한 다양한 시나리오를 설명하고 장기 실행 백그라운드 작업을 수행하고 원격 프로시저 호출에 대한 인터페이스를 제공하기 위해 서비스를 구현하는 방법을 보여 줍니다.

Android 서비스 개요

모바일 앱은 데스크톱 앱과 같지 않습니다. 데스크톱에는 화면 부동산, 메모리, 스토리지 공간 및 연결된 전원 공급 장치와 같은 풍부한 양의 리소스가 있으며 모바일 디바이스는 그렇지 않습니다. 이러한 제약 조건은 모바일 앱이 다르게 작동하도록 강제합니다. 예를 들어 모바일 디바이스의 작은 화면은 일반적으로 한 번에 하나의 앱(즉, 활동)만 볼 수 있음을 의미합니다. 다른 활동은 백그라운드로 이동하고 작업을 수행할 수 없는 일시 중단된 상태로 푸시됩니다. 그러나 Android 애플리케이션이 백그라운드에 있다고 해서 앱이 계속 작동할 수 없다는 의미는 아닙니다.

Android 애플리케이션은 활동, 브로드캐스트 수신기, 콘텐츠 공급자서비스의 네 가지 기본 구성 요소 중 하나 이상으로 구성됩니다. 활동은 사용자가 애플리케이션과 상호 작용할 수 있는 UI를 제공하기 때문에 많은 훌륭한 Android 애플리케이션의 초석입니다. 그러나 동시 또는 백그라운드 작업을 수행하는 경우 활동이 항상 최선의 선택은 아닙니다.

Android에서 백그라운드 작업을 위한 기본 메커니즘은 서비스입니다. Android 서비스는 사용자 인터페이스 없이 일부 작업을 수행하도록 설계된 구성 요소입니다. 서비스는 파일을 다운로드하거나, 음악을 재생하거나, 이미지에 필터를 적용할 수 있습니다. Android 애플리케이션 간의 IPC(프로세스 간 통신)에도 서비스를 사용할 수 있습니다. 예를 들어 한 Android 앱이 다른 앱의 음악 플레이어 서비스를 사용하거나 앱이 서비스를 통해 다른 앱에 데이터(예: 사용자의 연락처 정보)를 노출할 수 있습니다.

서비스와 백그라운드 작업을 수행하는 기능은 원활하고 유동적인 사용자 인터페이스를 제공하는 데 매우 중요합니다. 모든 Android 애플리케이션에는 활동이 실행되는 기본 스레드(UI 스레드라고도 함)가 있습니다. 디바이스 응답성을 유지하려면 Android에서 초당 60프레임 속도로 사용자 인터페이스를 업데이트할 수 있어야 합니다. Android 앱이 기본 스레드에서 너무 많은 작업을 수행하는 경우 Android는 프레임을 삭제합니다. 그러면 UI가 육포(janky라고도 함)가 나타납니다. 즉, UI 스레드에서 수행되는 모든 작업은 두 프레임 사이의 시간 범위에서 약 16밀리초(60프레임마다 1초)에 완료되어야 합니다.

이 문제를 해결하기 위해 개발자는 작업의 스레드를 사용하여 UI를 차단하는 일부 작업을 수행할 수 있습니다. 그러나 이로 인해 문제가 발생할 수 있습니다. Android가 활동의 여러 인스턴스를 삭제하고 다시 만들 수 있습니다. 그러나 Android는 스레드를 자동으로 삭제하지 않으므로 메모리 누수를 초래할 수 있습니다. 이 예제의 주요 예는 디바이스가 회전되는 경우입니다. Android는 활동 인스턴스를 삭제한 다음 새 인스턴스를 다시 만듭니다.

When device rotates, instance 1 is destroyed and instance 2 is created

이는 잠재적인 메모리 누수입니다. 작업의 첫 번째 인스턴스에서 만든 스레드는 계속 실행됩니다. 스레드에 작업의 첫 번째 인스턴스에 대한 참조가 있는 경우 Android에서 개체를 가비지 수집하지 못하게 됩니다. 그러나 활동의 두 번째 인스턴스는 여전히 만들어집니다(다시 새 스레드를 만들 수 있습니다). 디바이스를 여러 번 연속으로 회전하면 모든 RAM이 소모되고 Android가 전체 애플리케이션을 종료하여 메모리를 회수하도록 강제할 수 있습니다.

일반적으로 수행할 작업이 활동보다 오래 지속될 경우 해당 작업을 수행하기 위해 서비스를 만들어야 합니다. 그러나 작업 컨텍스트에서만 작업을 적용할 수 있는 경우 작업을 수행할 스레드를 만드는 것이 더 적합할 수 있습니다. 예를 들어 사진 갤러리 앱에 방금 추가된 사진에 대한 썸네일을 만드는 작업은 서비스에서 발생할 수 있습니다. 그러나 활동이 포그라운드에 있는 동안에만 들어야 하는 일부 음악을 재생하는 데 스레드가 더 적합할 수 있습니다.

백그라운드 작업은 다음 두 가지 광범위한 분류로 나눌 수 있습니다.

  1. 장기 실행 작업 – 명시적으로 중지될 때까지 진행 중인 작업입니다. 장기 실행 작업의 예로는 음악을 스트리밍하거나 센서에서 수집된 데이터를 모니터링해야 하는 앱이 있습니다. 애플리케이션에 표시되는 사용자 인터페이스가 없더라도 이러한 작업을 실행해야 합니다.
  2. 주기적 작업 – (작업이라고도 함) 주기적 작업은 비교적 짧은 기간(몇 초)이며 일정에 따라 실행됩니다(예: 일주일에 한 번 또는 다음 60초에 한 번만 실행). 예를 들어 인터넷에서 파일을 다운로드하거나 이미지에 대한 썸네일을 생성합니다.

Android 서비스에는 다음과 같은 네 가지 유형이 있습니다.

  • 바인딩된 서비스 - 바인딩된 서비스는 다른 구성 요소(일반적으로 활동)가 바인딩된 서비스입니다. 바인딩된 서비스는 바인딩된 구성 요소와 서비스가 서로 상호 작용할 수 있도록 하는 인터페이스를 제공합니다. 서비스에 바인딩된 클라이언트가 더 이상 없으면 Android에서 서비스를 종료합니다.

  • IntentService – 서비스 IntentService 만들기 및 사용을 간소화하는 클래스의 Service 특수 하위 클래스입니다. 개별 IntentService 자율 호출을 처리하기 위한 것입니다. 여러 호출 IntentService 을 동시에 처리할 수 있는 서비스와 달리 작업 큐 프로세서와 비슷합니다. 작업이 큐에 대기되고 IntentService 각 작업을 단일 작업자 스레드에서 한 번에 하나씩 처리합니다. 일반적으로 활동IntentService 또는 조각에 바인딩되지 않습니다.

  • 시작 서비스 - 시작된 서비스는 일부 다른 Android 구성 요소(예: 활동)에서 시작한 서비스이며, 명시적으로 서비스에 중지를 지시할 때까지 백그라운드에서 계속 실행됩니다. 바운드 서비스와 달리 시작된 서비스에는 클라이언트가 직접 바인딩되지 않습니다. 이러한 이유로 필요에 따라 정상적으로 다시 시작될 수 있도록 시작된 서비스를 디자인하는 것이 중요합니다.

  • 하이브리드 서비스하이브리드 서비스는 시작된 서비스와 바인딩된 서비스의 특성을 가진 서비스입니다. 하이브리드 서비스는 구성 요소가 바인딩되거나 일부 이벤트에 의해 시작될 수 있는 경우에 시작할 수 있습니다. 클라이언트 구성 요소는 하이브리드 서비스에 바인딩되거나 바인딩되지 않을 수 있습니다. 하이브리드 서비스는 명시적으로 중지하라는 메시지가 나 바인딩된 클라이언트가 더 이상 없을 때까지 계속 실행됩니다.

사용할 서비스 유형은 애플리케이션 요구 사항에 따라 크게 달라집니다. 일반적으로 IntentService Android 애플리케이션이 수행해야 하는 대부분의 작업에는 바인딩된 서비스 또는 바인딩된 서비스가 충분하므로 이러한 두 가지 유형의 서비스 중 하나에 기본 설정을 지정해야 합니다. 파일 IntentService 다운로드와 같은 "원샷" 작업에 적합한 반면, 활동/조각과의 빈번한 상호 작용이 필요한 경우 바인딩된 서비스가 적합합니다.

대부분의 서비스는 백그라운드에서 실행되지만 포그라운드 서비스라고 하는 특수 하위 범주가 있습니다. 이 서비스는 사용자(예: 음악 재생)를 위해 일부 작업을 수행하기 위해 더 높은 우선 순위(일반 서비스에 비해)가 부여되는 서비스입니다.

동일한 디바이스에서 자체 프로세스에서 서비스를 실행할 수도 있습니다. 이를 원격 서비스 또는 Out-of-process 서비스라고도 합니다. 이렇게 하려면 만드는 데 더 많은 노력이 필요하지만 애플리케이션이 다른 애플리케이션과 기능을 공유해야 하는 경우에 유용할 수 있으며 경우에 따라 애플리케이션의 사용자 환경을 개선할 수 있습니다.

Android 8.0의 백그라운드 실행 제한

Android 8.0(API 수준 26)부터 Android 애플리케이션은 더 이상 백그라운드에서 자유롭게 실행할 수 없습니다. 포그라운드에 있는 경우 앱은 제한 없이 서비스를 시작하고 실행할 수 있습니다. 애플리케이션이 백그라운드로 이동하면 Android는 앱에 서비스를 시작하고 사용하는 데 일정한 시간을 부여합니다. 해당 시간이 경과하면 앱은 더 이상 서비스를 시작할 수 없으며 시작된 모든 서비스가 종료됩니다. 이 시점에서 앱이 작업을 수행할 수 없습니다. Android는 다음 조건 중 하나가 충족되는 경우 애플리케이션이 포그라운드에 있는 것으로 간주합니다.

  • 표시되는 작업(시작 또는 일시 중지)이 있습니다.
  • 앱이 포그라운드 서비스를 시작했습니다.
  • 다른 앱은 포그라운드에 있으며 백그라운드에 있는 앱의 구성 요소를 사용하고 있습니다. 예를 들어 포그라운드에 있는 애플리케이션 A가 애플리케이션 B에서 제공하는 서비스에 바인딩된 경우입니다. 애플리케이션 B는 포그라운드에서도 고려되고 백그라운드에서 Android에서 종료되지 않습니다.

앱이 백그라운드에 있더라도 Android에서 앱을 해제하고 몇 분 동안 이러한 제한을 완화하여 앱이 몇 가지 작업을 수행할 수 있도록 하는 몇 가지 상황이 있습니다.

  • 앱에서 우선 순위가 높은 Firebase 클라우드 메시지를 받습니다.
  • 앱이 브로드캐스트를 받습니다.
  • 애플리케이션은 알림에 대한 응답으로 A PendingIntent 를 수신하고 실행합니다.

기존 Xamarin.Android 애플리케이션은 Android 8.0에서 발생할 수 있는 문제를 방지하기 위해 백그라운드 작업을 수행하는 방법을 변경해야 할 수 있습니다. Android 서비스에 대한 몇 가지 실용적인 대안은 다음과 같습니다.

  • Android 작업 스케줄러 또는 Firebase 작업 디스패처를 사용하여 백그라운드에서 실행되도록 작업 예약 – 이 두 라이브러리는 애플리케이션이 백그라운드 작업을 작업으로 분리하기 위한 프레임워크, 즉 개별 작업 단위를 제공합니다. 그런 다음 앱은 작업을 실행할 수 있는 시기에 대한 몇 가지 기준과 함께 운영 체제를 사용하여 작업을 예약할 수 있습니다.
  • 포그라운드 에서 서비스를 시작합니다. 포그라운드 서비스는 앱이 백그라운드에서 일부 작업을 수행해야 하고 사용자가 해당 작업과 주기적으로 상호 작용해야 하는 경우에 유용합니다. 포그라운드 서비스는 사용자가 앱이 백그라운드 작업을 실행하고 있음을 인식하고 작업을 모니터링하거나 상호 작용하는 방법을 제공하므로 영구 알림을 표시합니다. 예를 들어 사용자에게 팟캐스트를 재생하거나 나중에 즐길 수 있도록 팟캐스트 에피소드를 다운로드하는 팟캐스트 앱이 있습니다.
  • 높은 우선 순위의 FCM(Firebase Cloud Message) 사용 – Android가 앱에 대해 높은 우선 순위의 FCM을 받으면 해당 앱이 짧은 시간 동안 백그라운드에서 서비스를 실행할 수 있습니다. 백그라운드에서 앱을 폴링하는 백그라운드 서비스를 사용하는 것이 좋습니다.
  • 앱이 포그라운드에 들어올 때 작업 지연 – 이전 솔루션이 실행 가능하지 않은 경우 앱이 포그 라운드에 올 때 작업을 일시 중지하고 다시 시작하는 고유한 방법을 개발해야 합니다.