오프스크린 상태에서 앱의 효율성 높이기 - 백그라운드 작업

이전 글(오프스크린 상태에서 앱의 효율성 높이기(1부))에서 Windows 8 백그라운드 모델을 소개하고 앱이 화면에 표시되지 않을 때에도 전원 효율성을 극대화하여 생산성을 높일 수 있는 방법을 설명했습니다. 2부에서는 백그라운드 작업에 대해서 알아보고 앱이 일시 중단된 상태에서도 백그라운드에서 코드가 실행되는 원리를 설명하겠습니다. 이해를 돕기 위해 앱 코드를 백그라운드에서 실행하는 방법을 두 가지 일반적인 시나리오에서 예제 코드와 함께 설명합니다. 그중 하나는 잠금 화면을 지원하는 앱을 사용해 15분마다 POP 이메일을 다운로드하는 방법을 보여 주는 시나리오이고 다른 하나는 장치가 AC 전원에 연결되어 있을 때 앱에서 백그라운드 작업이 어떻게 실행되는지를 보여 줍니다.

소개

백그라운드 작업 트리거마다 적용되는 시나리오와 용도가 다르고, 요구 사항과 리소스 관리상의 제약도 다양하게 적용됩니다. 예를 들어 항상 최신 상태로 유지해야 하는 앱(예: 이메일 및 VOIP)에 사용하도록 고안된 백그라운드 작업 트리거도 있고, 그보다는 특정 조건이나 상황에만 적용되는 백그라운드 작업 트리거(예: AC 전원에 연결되어 있을 때 또는 특정 시스템 조건이 변경되었을 때 유지 관리 작업 실행)도 있습니다. 항상 최신으로 유지되어야 하는 앱의 경우 잠금 화면에 포함되어야 합니다. 단, 잠금 화면에는 앱을 7개까지만 추가할 수 있습니다. 자세한 내용은 이 글의 뒷부분에서 설명하겠습니다. 반면, 조건이나 상황에 따라 작업을 수행할 경우에는 어떤 앱에서든 유지 관리 트리거를 사용해 AC 또는 특정 시스템 트리거를 실행할 수 있습니다. 이러한 트리거를 사용할 때는 앱을 잠금 화면에 추가할 필요가 없습니다. 잠금 화면에 추가된 앱은 상대적으로 자주 실행되어야 하기 때문에 리소스 관리상의 제약 조건이 덜 까다롭게 적용됩니다. 추가할 수 있는 앱 수를 제한하고 사용자가 관리하도록 한 것도 이 때문입니다. 자세한 내용은 뒷부분에서 설명하겠습니다.

단순히 앱의 콘텐츠를 최신으로 유지하려는 경우에는 백그라운드 작업을 사용할 필요가 없습니다. 뛰어난 라이브 타일 환경 만들기(1부)에서 설명했듯이 라이브 타일이나 알림 스케줄링을 사용하면 됩니다. 그럼 소개는 이 정도로 하고 이제 본격적으로 코드를 살펴보겠습니다.

장치가 AC 전원에 연결된 상태에서의 작업

1부에서 살펴보았듯이 백그라운드에서 기능을 제공하려면 앱 자체에 코드가 필요한 경우도 있습니다. 일례로 사진 라이브러리의 모든 사진을 앱 데이터베이스에 추가하거나, 미리 보기를 생성하는 등의 방식으로 처리해야 한다고 가정해 봅니다. 앱이 포그라운드로 실행 중이고 사용자가 앱을 조작하고 있을 때 이러한 작업을 수행할 수도 있고, 장치가 AC 전원에 연결되어 있는 경우에만 백그라운드로 실행되는 유지 관리 트리거를 사용해 백그라운드 작업으로 수행할 수도 있습니다. 유지 관리 트리거는 모든 사용자가 사용할 수 있고 앱이 잠금 화면에 추가된 상태가 아니어도 됩니다. 유지 관리 트리거 백그라운드 작업의 장점은 어떤 경우에도 사용자의 작업을 방해하지 않고 AC 전원에 연결되어 있는 경우에만 실행되기 때문에 배터리를 과도하게 소모할 염려가 없다는 점입니다.

아래 코드 예제는 실행될 경우 ProcessPictures 클래스를 호출하여 파일을 처리하는 유지 관리 백그라운드 작업을 보여 줍니다. 이 작업은 8시간 마다 실행되어 처리할 새 파일이 있는지 확인합니다. 유지 관리 백그라운드 작업은 장치가 배터리 전원을 사용하는 상태로 바뀌면 취소되기 때문에 취소 처리 기능에도 등록됩니다. 이 경우 취소 처리 기능에서 파일 처리 작업이 취소됩니다. 취소 처리 기능에 등록된 상태에서 5초 이상 변화가 없으면 Windows가 앱을 자동으로 종료합니다. 이 코드 예제는 백그라운드 작업과 트리거 클래스에 대한 기본 지식이 있는 개발자를 대상으로 합니다. 이러한 클래스에 대한 자세한 내용은 개발자 센터에서 Windows.ApplicationModel.Background 네임스페이스 설명서를 참조하세요.

C#
 public sealed class MaintenanceBackgroundTask: IBackgroundTask
{
    private ProcessPictures processPic; 
 
    public MaintenanceBackgroundTask()
    {
        // Code to process the pictures 
processPic = new ProcessPictures(); 
    }

    //Main Run method which is activated every 8 hours
   async void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
    {
        taskInstance.Canceled += taskInstance_Canceled;

// Because these methods are async, you must use a deferral 
        // to wait for all of them to complete
        BackgroundTaskDeferral deferral = taskInstance.GetDeferral(); 
        List<StorageFile> list = new List<StorageFile>();
        int count = await processPic.EnumerateFiles(list);
        bool retval = await processPic.ProcessFiles(list); 
        
        deferral.Complete(); 
    }

    // Cancel handler, called whenever the task is canceled
    void taskInstance_Canceled(IBackgroundTaskInstance sender, 
            BackgroundTaskCancellationReason reason)
    {
        // Device is now on DC power, cancel processing of files 
        processPic.Cancel = true; 
    }
}

 

JavaScript
 // This JS lives within maintenanceBackgroundTask.js
var processPic = new processPictures();
var count = 0;
var retval = false;

function onCanceled(cancelSender, cancelReason) {
    // Device is now on DC power, cancel processing of files
    processPic.cancel = true;
}
backgroundTaskInstance.addEventListener("canceled", onCanceled);

var list = [];
processPic.enumerateFiles(list).then(function (value) {
    count = value;
    processPic.processFiles(list).then(function (value) {
        retval = value;
// Call close() to indicate the task is complete when 
// all async methods have completed
        close();
    });
});

                   

아래 코드 예제는 메인 앱에서 유지 관리 백그라운드 작업을 등록하는 방법을 보여 줍니다. 예제의 백그라운드 작업은 8시간마다 실행되어 사진 라이브러리의 모든 사진을 처리합니다. 이 작업을 더 이상 실행할 필요가 없을 때는 IBackgroundTaskRegistration 클래스의 Unregister 메서드를 사용하여 백그라운드 작업을 등록 취소할 수 있습니다.

C#
 //Registering the maintenance trigger background task       
private bool RegisterMaintenanceBackgroundTask()
        {
            BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
            builder.Name = "Maintenance background task"; 
            builder.TaskEntryPoint = "MaintenanceTask.MaintenaceBackgroundTask";
            // Run every 8 hours if the device is on AC power 
            IBackgroundTrigger trigger = new MaintenanceTrigger(480, false);
            builder.SetTrigger(trigger); 
            IBackgroundTaskRegistration task = builder.Register(); 

            return true;
        }

 

JavaScript
 function registerMaintenanceBackgroundTask() 
{
    var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
    builder.name = "Maintenance background task";
    builder.taskEntryPoint = "js\\maintenanceBackgroundTask.js";
    //Run every 8 hours if the device is on AC power
    var trigger = new Windows.ApplicationModel.Background.MaintenanceTrigger(480, false);
    builder.setTrigger(trigger);
    var task = builder.register();

    return true;
}

백그라운드 작업은 앱 매니페스트에 선언해야 합니다. 먼저 Visual Studio에서 앱의 매니페스트를 열고 [선언] 탭의 드롭다운 메뉴에서 [백그라운드 작업] 선언을 추가합니다. 적절한 작업 유형을 선택하고 진입점(백그라운드 작업의 클래스 이름)을 지정하거나 JavaScript 백그라운드 작업을 사용하는 경우 시작 페이지를 지정합니다.

백그라운드 작업 매니페스트 선언 
그림 1 - 백그라운드 작업 매니페스트 선언

매니페스트의 내용은 마우스 오른쪽 단추로 클릭하고 [코드 보기]를 선택하면 확인할 수 있습니다. 유지 관리 작업은 시스템에서 제공하는 호스트(backgroundTaskHost.exe, 또는 JavaScript의 경우 wwahost.exe)에서만 실행할 수 있으므로 Executable 특성은 지정할 수 없습니다. 다음 매니페스트 코드 조각에서 보듯이 유지 관리 트리거의 작업 유형은 systemEvent입니다.

 <Extension Category="windows.backgroundTasks" EntryPoint="MaintenanceTask.MaintenaceBackgroundTask">
         <BackgroundTasks>
           <Task Type="systemEvent" />
         </BackgroundTasks>
       </Extension>

JavaScript의 경우 EntryPoint가 StartPage 특성으로 대체됩니다.

 <Extension Category="windows.backgroundTasks" StartPage="js\maintenaceBackgroundTask.js">

백그라운드 작업의 사용 방법을 자세히 알아보려면 백그라운드 작업 소개 백서 및 개발자 센터에서 제공되는 API 사용 방법을 참조하십시오.

15분마다 POP 메일 다운로드

이 예제에서는 정해진 조건에 따라 백그라운드에서 주기적으로 실행되는 앱이 필요합니다. 이를 구현하려면 앱을 잠금 화면에 추가하면 됩니다.

앱에서 백그라운드 작업을 사용하는 이유는 사용자가 Windows 8 장치를 사용하지 않을 때에도 앱을 항상 최신으로 유지하기 위해서이므로, 사용자는 원하는 앱을 잠금 화면에 표시되도록 추가하는 방식으로 이러한 백그라운드 작업을 사용할 앱을 결정하게 됩니다. 잠금 화면은 사용자가 Windows 8 장치를 잠금 해제하지 않고도 앱에 대한 정보를 확인할 수 있게 고안된 기능이기 때문에 이러한 제어 방식이 자연스럽게 들어맞는다고 할 수 있습니다. 앱과 잠금 화면은 양방향으로 상호 작용합니다. 즉, 앱은 잠금 화면에 추가된 경우에만 이러한 유형의 백그라운드 작업을 사용할 수 있고, 마찬가지로 앱에서 이러한 백그라운드 작업을 사용하도록 요청하는 경우에만 잠금 화면에 앱이 표시됩니다.

background2_img2

그림 2 - 잠금 화면 개인 설정 UI와 잠금 화면 지원 앱

잠금 화면에 추가할 수 있는 앱의 수가 적기 때문에 앱에서 뛰어난 잠금 화면 환경을 제공하도록 하는 것이 중요합니다. 그렇지 않으면 사용자가 다른 앱을 추가하기 위해 잠금 화면에서 제거할 수 있습니다. 읽지 않은 이메일 메시지의 수를 표시하는 메일 앱과 같은 통신 앱, 자세한 상태 슬롯을 통해 예정된 약속을 보여 주는 일정 앱, 사용자가 확인하지 않은 메시지 수를 보여 주는 메시지 앱 등이 사용자가 잠금 화면에 기꺼이 추가할 만한 앱의 좋은 예라 하겠습니다. 잠금 화면에 추가할 만한 앱으로 만드는 방법을 비롯하여 잠금 화면에 대한 자세한 내용은 개발자 센터를 참조하십시오.

시간 트리거를 사용하여 15분마다 메일 다운로드

아래 예제 코드는 인터넷 연결이 가능한 경우 15분마다 실행되는 시간 트리거 백그라운드 작업을 BackgroundTaskBuilder 클래스를 사용하여 등록하는 방법을 보여 줍니다. 인터넷에 연결할 수 없는 경우에는 백그라운드 작업이 실행되지 않고 인터넷 연결이 가능해질 때까지 기다린 후 자동으로 실행됩니다. 백그라운드 작업의 이러한 기능은 불필요하게 작업을 실행하여 장치의 배터리를 소모하지 않도록 한다는 점에서 유용합니다. 이 조건이 없다면 코드가 실행되고 네트워크에 연결되지 않은 상태를 감지한 후 메일을 다운로드할 수 없다는 오류가 발생하게 됩니다. 그리고 앱이 포그라운드로 실행 중인지 여부에 관계없이 메일이 다운로드됩니다. 또한 장치가 온라인 대기 모드 상태일 때도 메일이 다운로드됩니다.

C#
 private bool RegisterTimeTriggerBackgroundTask()
        {
            BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
            builder.Name = "Pop mail background task";
            builder.TaskEntryPoint = "MailClient.PopMailBackgroundTask";
            // Run every 15 minutes if the device has internet connectivity
            IBackgroundTrigger trigger = new TimeTrigger(15, false);
            builder.SetTrigger(trigger);
            IBackgroundCondition condition = 
                new SystemCondition(SystemConditionType.InternetAvailable);
            builder.AddCondition(condition); 
            IBackgroundTaskRegistration task = builder.Register();

            return true;
        }
JavaScript
 function registerTimeTriggerBackgroundTask() 
   {
       var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
       builder.name = "Pop mail background task";
       builder.taskEntryPoint = "js\\popMailBackgroundTask.js";
       //Run every 15 minutes if the device has internet connectivity
       var trigger = new Windows.ApplicationModel.Background.TimeTrigger(15, false);
       builder.setTrigger(trigger);
       var condition = new Windows.ApplicationModel.Background.SystemCondition(                             
Windows.ApplicationModel.Background.SystemConditionType.internetAvailable);
       builder.addCondition(condition);
       var task = builder.register();

       return true;
   }

앞서 설명했듯이 시간 트리거도 앱이 잠금 화면에 추가되어 있을 때만 사용할 수 있습니다. 프로그래밍 방식으로 앱을 잠금 화면에 추가하도록 요청하려면 BackgroundExecutionManager 클래스를 사용해야 합니다. 사용자가 앱을 잠금 화면에 추가하지 않으면 백그라운드 작업은 실행되지 않습니다. 이 경우 잠금 화면에 앱을 추가할 필요가 없는 백그라운드 작업을 사용하거나 사용자가 앱을 사용 중일 때 작업을 수행하는 방식으로 대체해야 합니다. 즉, 잠금 화면에 추가할지를 여부를 사용자에게 반복해 묻지 않고 시스템에서 한 번만 묻도록 합니다. 사용자가 추가하지 않도록 선택한 경우에도 나중에 수동으로 추가할 수 있습니다.

C#
 public async Task<bool> ObtainLockScreenAccess()
        {
            BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
            
            if (status == BackgroundAccessStatus.Denied || status == BackgroundAccessStatus.Unspecified)
            {
                return false; 
            }

            return true; 
        }

 

JavaScript
 function obtainLockScreenAccess()
   {
       Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync().then(function (status) {
           if (status === Windows.ApplicationModel.Background.BackgroundAccessStatus.denied || 
               status === Windows.ApplicationModel.Background.BackgroundAccessStatus.unspecified){
               return false;
           }
           return true;
       });
   }

아래 코드 예제는 15분마다 이메일을 다운로드하는 기본 백그라운드 작업을 보여 줍니다. 앱의 타일과 배지를 업데이트하는 방법은 뛰어난 라이브 타일 환경 만들기라는 블로그 글에서 이미 다루었으므로 여기서는 자세히 설명하지 않습니다.

C#
 void IBackgroundTask.Run(IBackgroundTaskInstance taskInstance)
        {
            int count = popmailClient.GetNewMails(); 
            // Update badge on lock screen with the mail count 
            popmailClient.UpdateLockScreenBadgeWithNewMailCount(count);

            IList<string> mailheaders = popmailClient.GetNewMailHeaders(); 
            // Update app tile with the subjects of the email 
            popmailClient.UpdateTileWithSubjects(mailheaders); 
        }

 

JavaScript
 //This JS lives within popMailBackgroundTask.js
    var count = popmailClient.getNewMails();
    // Update badge on lock screen with the mail count
    popmailClient.updateLockScreenBadgeWithNewmailCount(count);

    var mailheaders = popmailClient.getnewMailHeaders();
    // Update app tile with the subjects of the email
    popmailClient.updatetileWithSubjects(mailheaders);
    close();

앱을 잠금 화면에 추가하려면 매니페스트의 [응용 프로그램 UI] 탭에서 사용 가능한 잠금 화면 알림 유형을 지정해야 합니다.

그림 3 - 백그라운드 작업 매니페스트 선언

아래에는 잠금 화면에 추가되어야 하고 잠금 화면에 배지와 알림을 표시하는 앱의 매니페스트 코드 조각(마법사에서 생성)입니다. 시간 트리거 작업은 시스템에서 제공하는 호스트(backgroundTaskHost.exe, 또는 JavaScript의 경우 wwahost.exe)에서만 실행할 수 있으므로 Executable 특성은 지정할 수 없습니다. 매니페스트에서 보듯이 작업 유형은 timer입니다.

 <LockScreen Notification="badgeAndTileText" BadgeLogo="Images\badgelogo.png" />
      <DefaultTile ShowName="allLogos" WideLogo="Images\tile-sdk.png" ShortName="LockScreen CS" />
      <SplashScreen Image="Images\splash-sdk.png" BackgroundColor="#FFFFFF" />
    </VisualElements>
    <Extensions>
      <Extension Category="windows.backgroundTasks" EntryPoint="MailClient.PopMailBackgroundTask">
        <BackgroundTasks>
          <Task Type="timer" />
        </BackgroundTasks>
      </Extension>

JavaScript의 경우 EntryPoint가 StartPage 특성으로 대체됩니다.

 <Extension Category="windows.backgroundTasks" StartPage="js\popMailBackgroundTask.js"

 

고급 시나리오

컨트롤 채널 트리거, 푸시 알림 트리거 등 다른 백그라운드 작업 트리거를 사용하여 좀 더 고급화된 VOIP, 인스턴트 메시지 또는 푸시 메일 앱을 만들 수 있습니다. 이러한 트리거의 사용법은 이 글의 주제를 벗어나는 내용이므로 여기서는 다루지 않습니다. 자세한 내용은 백그라운드 네트워킹 백서를 참조하십시오.

백그라운드 작업의 리소스 관리

이미 설명했듯이 백그라운드 작업은 전원 효율을 극대화하도록 고안되었기 때문에 CPU와 네트워크 리소스의 사용에 제약이 있습니다. 이러한 리소스 사용상의 제약은 백그라운드로 실행되는 앱이 사용자가 모르는 사이에 장치의 배터리를 급격하게 소모시키지 않도록 하기 위한 장치입니다. 앱이 활성 상태이고 사용자가 포그라운드로 앱을 조작하고 있을 때에는 앱의 백그라운드 작업에 CPU나 네트워크 리소스의 제한이 적용되지 않습니다.

CPU 리소스 제한

잠금 화면에 있는 앱은 각각 15분마다 2초씩 CPU 시간을 할당받습니다. 이 CPU 시간은 앱의 모든 백그라운드 작업에 사용할 수 있습니다. 그리고 15분이 경과하면 잠금 화면에 있는 각각의 앱이 다시 2초씩 백그라운드 작업에 사용할 CPU 시간을 할당받습니다. 15분 간격으로 사용되지 않은 CPU 시간은 소실되며 누적되지 않습니다. 잠금 화면에 추가되지 않은 앱은 각각 2시간마다 1초씩 CPU 시간을 할당받습니다. 앱이 사용 가능한 CPU 시간을 모두 소진하면 다음 CPU 할당량 업데이트 주기 때 앱의 CPU 할당량이 다시 채워질 때까지 백그라운드 작업이 일시 중단됩니다.

CPU 사용 시간이란 백그라운드 작업 소요 시간이 아니라 앱에서 실제 사용된 CPU의 양을 말합니다. 예를 들어 백그라운드 작업이 코드 실행 중에 원격 서버의 응답을 기다릴 때는 CPU를 실제로 사용하고 있지 않으므로 이 대기 시간은 CPU 할당량에 반영되지 않습니다.

백그라운드 작업에 대한 CPU 리소스 제한

 

CPU 리소스 할당량

새로 고침 기간

잠금 화면 지원 앱

CPU 시간 2초

15분

잠금 화면을 지원하지 않는 앱

CPU 시간 1초

2시간

네트워크 리소스 제한

네트워크를 사용할 경우 장치의 배터리를 많이 소모하기 때문에 백그라운드 작업을 실행하는 동안 네트워크 사용도 제한됩니다. 단, AC 전원으로 장치를 실행하는 중에는 백그라운드 작업에 대해 네트워크 사용이 제한되지 않습니다. 반면 백그라운드 작업의 CPU 사용은 AC 전원으로 장치를 실행하는 동안에도 항상 제한됩니다.

아래 표는 간섭이 최소한이라고 가정했을 때 리소스 사용이 제한된 WiFi 네트워크의 네트워크 데이터 처리량 특성을 보여 줍니다.

 

전역 풀

앱마다 지정된 할당량이 있지만 이렇게 한정된 리소스만으로는 부족한 경우도 있습니다. 그러한 경우를 대비해 응용 프로그램이 CPU 및 네트워크 리소스를 요청할 수 있는 공유 전역 풀이 제공됩니다.

백그라운드 작업, 전역 풀, 리소스 관리상의 제약, 모범 사례 등은 백그라운드 작업 소개 백서에서 참조할 수 있습니다. 여기에는 샘플 프로젝트와 소스 코드도 포함되어 있습니다.

요약

지금까지 살펴본 바와 같이 '앱이 화면에 표시되지 않은 상태에서도 작업을 실행할 수 있는가'라는 질문의 대답은 '그렇다'입니다. Windows 8의 백그라운드 모델은 앱이 파일 다운로드, 오디오 재생, 이메일 업데이트 등의 주요한 최종 사용자 작업을 백그라운드로 수행하거나 장치가 AC 전원으로 작동할 때 유지 관리 작업을 수행할 수 있도록 지원합니다. 또한 이러한 작업이 플랫폼에서 자세히 모니터링되기 때문에 백그라운드 작업은 포그라운드 앱의 응답 성능이나 장치의 배터리 수명에 거의 영향을 미치지 않습니다.

Windows 8의 백그라운드 모델에 대한 자세한 내용은 개발자 센터에서 다양한 백서를 참조하시기 바랍니다. 질문은 댓글로 남겨 주시면 성심껏 답변해 드리겠습니다.

- Windows 프로그램 관리자, Hari Pulapaka

도움을 주신 Jake Sabulsky, Johnny Bregar, Kyle Beck 그리고 Suhail Khalid에게 감사드립니다. 좋은 의견을 주신 Alexander Corradini, Arun Kishan, Ben Srour, Ian LeGrow, Jamie Schwartz, John Sheehan에게도 감사의 마음을 전합니다.

리소스

링크

유형

주요 내용

백그라운드 작업 소개

백서

백그라운드 작업을 소개합니다.

백그라운드 모델 API 네임스페이스

문서

백그라운드 모델의 API 네임스페이스를 설명합니다.

백그라운드 작업 샘플 프로젝트

프로젝트 샘플

백그라운드 작업의 사용 방법을 보여 줍니다.

잠금 화면 개요

도움말

잠금 화면과 그 모범 사례에 대해 설명합니다.

백그라운드 네트워킹

백서

백그라운드 작업을 사용하여 VOIP, 인스턴트 메시징 등의 고급 앱을 개발하는 방법을 보여 줍니다.

뛰어난 라이브 타일 환경 만들기(1부)

블로그 글

뛰어난 타일 환경을 만드는 방법을 보여 줍니다.