Membuat dan mendaftarkan tugas latar belakang di luar proses

API penting

Buat kelas tugas latar belakang dan daftarkan untuk dijalankan saat aplikasi Anda tidak berada di latar depan. Topik ini menunjukkan cara membuat dan mendaftarkan tugas latar belakang yang berjalan dalam proses terpisah daripada proses aplikasi Anda. Untuk melakukan pekerjaan latar belakang langsung di aplikasi latar depan, lihat Membuat dan mendaftarkan tugas latar belakang dalam proses.

Catatan

Jika Anda menggunakan tugas latar belakang untuk memutar media di latar belakang, lihat Memutar media di latar belakang untuk informasi tentang peningkatan di Windows 10, versi 1607, yang membuatnya jauh lebih mudah.

Catatan

Jika Anda menerapkan tugas latar belakang di luar proses di aplikasi desktop C# dengan .NET 6 atau yang lebih baru, maka gunakan dukungan penulisan C#/WinRT untuk membuat Komponen Windows Runtime. Ini berlaku untuk aplikasi yang menggunakan SDK Aplikasi Windows, WinUI 3, WPF, atau WinForms. Lihat contoh tugas Latar Belakang misalnya.

Membuat kelas Tugas Latar Belakang

Anda dapat menjalankan kode di latar belakang dengan menulis kelas yang mengimplementasikan antarmuka IBackgroundTask . Kode ini berjalan ketika peristiwa tertentu dipicu dengan menggunakan, misalnya, SystemTrigger atau MaintenanceTrigger.

Langkah-langkah berikut menunjukkan kepada Anda cara menulis kelas baru yang mengimplementasikan antarmuka IBackgroundTask .

  1. Buat proyek baru untuk tugas latar belakang dan tambahkan ke solusi Anda. Untuk melakukan ini, klik kanan pada simpul solusi Anda di Penjelajah Solusi dan pilih Tambahkan>Proyek Baru. Kemudian pilih jenis proyek Komponen Runtime Windows , beri nama proyek, dan klik OK.
  2. Referensikan proyek tugas latar belakang dari proyek aplikasi Platform Windows Universal (UWP) Anda. Untuk aplikasi C# atau C++, di proyek aplikasi Anda, klik kanan Referensi dan pilih Tambahkan Referensi Baru. Di bawah Solusi, pilih Proyek lalu pilih nama proyek tugas latar belakang Anda dan klik Ok.
  3. Ke proyek tugas latar belakang, tambahkan kelas baru yang mengimplementasikan antarmuka IBackgroundTask . Metode IBackgroundTask.Run adalah titik masuk yang diperlukan yang akan dipanggil ketika peristiwa yang ditentukan dipicu; metode ini diperlukan di setiap tugas latar belakang.

Catatan

Kelas tugas latar belakang itu sendiri—dan semua kelas lain dalam proyek tugas latar belakang—harus kelas publik yang disegel (atau final).

Contoh kode berikut menunjukkan titik awal yang sangat mendasar untuk kelas tugas latar belakang.

// ExampleBackgroundTask.cs
using Windows.ApplicationModel.Background;

namespace Tasks
{
    public sealed class ExampleBackgroundTask : IBackgroundTask
    {
        public void Run(IBackgroundTaskInstance taskInstance)
        {
            
        }        
    }
}
// First, add ExampleBackgroundTask.idl, and then build.
// ExampleBackgroundTask.idl
namespace Tasks
{
    [default_interface]
    runtimeclass ExampleBackgroundTask : Windows.ApplicationModel.Background.IBackgroundTask
    {
        ExampleBackgroundTask();
    }
}

// ExampleBackgroundTask.h
#pragma once

#include "ExampleBackgroundTask.g.h"

namespace winrt::Tasks::implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask>
    {
        ExampleBackgroundTask() = default;

        void Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance);
    };
}

namespace winrt::Tasks::factory_implementation
{
    struct ExampleBackgroundTask : ExampleBackgroundTaskT<ExampleBackgroundTask, implementation::ExampleBackgroundTask>
    {
    };
}

// ExampleBackgroundTask.cpp
#include "pch.h"
#include "ExampleBackgroundTask.h"

namespace winrt::Tasks::implementation
{
    void ExampleBackgroundTask::Run(Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
    {
        throw hresult_not_implemented();
    }
}
// ExampleBackgroundTask.h
#pragma once

using namespace Windows::ApplicationModel::Background;

namespace Tasks
{
    public ref class ExampleBackgroundTask sealed : public IBackgroundTask
    {

    public:
        ExampleBackgroundTask();

        virtual void Run(IBackgroundTaskInstance^ taskInstance);
        void OnCompleted(
            BackgroundTaskRegistration^ task,
            BackgroundTaskCompletedEventArgs^ args
        );
    };
}

// ExampleBackgroundTask.cpp
#include "ExampleBackgroundTask.h"

using namespace Tasks;

void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
}
  1. Jika Anda menjalankan kode asinkron di tugas latar belakang Anda, maka tugas latar belakang Anda perlu menggunakan penolakan. Jika Anda tidak menggunakan penangguhan, maka proses tugas latar belakang dapat berakhir secara tiba-tiba jika metode Jalankan kembali sebelum pekerjaan asinkron telah berjalan hingga selesai.

Minta penangguhan dalam metode Jalankan sebelum memanggil metode asinkron. Simpan deferral ke anggota data kelas sehingga dapat diakses dari metode asinkron. Nyatakan penolakan selesai setelah kode asinkron selesai.

Kode sampel berikut mendapatkan deferral, menyimpannya, dan merilisnya ketika kode asinkron selesai.

BackgroundTaskDeferral _deferral; // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation
public async void Run(IBackgroundTaskInstance taskInstance)
{
    _deferral = taskInstance.GetDeferral();
    //
    // TODO: Insert code to start one or more asynchronous methods using the
    //       await keyword, for example:
    //
    // await ExampleMethodAsync();
    //

    _deferral.Complete();
}
// ExampleBackgroundTask.h
...
private:
    Windows::ApplicationModel::Background::BackgroundTaskDeferral m_deferral{ nullptr };

// ExampleBackgroundTask.cpp
...
Windows::Foundation::IAsyncAction ExampleBackgroundTask::Run(
    Windows::ApplicationModel::Background::IBackgroundTaskInstance const& taskInstance)
{
    m_deferral = taskInstance.GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.
    // TODO: Modify the following line of code to call a real async function.
    co_await ExampleCoroutineAsync(); // Run returns at this point, and resumes when ExampleCoroutineAsync completes.
    m_deferral.Complete();
}
void ExampleBackgroundTask::Run(IBackgroundTaskInstance^ taskInstance)
{
    m_deferral = taskInstance->GetDeferral(); // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation.

    //
    // TODO: Modify the following line of code to call a real async function.
    //       Note that the task<void> return type applies only to async
    //       actions. If you need to call an async operation instead, replace
    //       task<void> with the correct return type.
    //
    task<void> myTask(ExampleFunctionAsync());

    myTask.then([=]() {
        m_deferral->Complete();
    });
}

Catatan

Di C#, metode asinkron tugas latar belakang Anda dapat dipanggil menggunakan kata kunci asinkron/menunggu . Dalam C++/CX, hasil serupa dapat dicapai dengan menggunakan rantai tugas.

Untuk informasi selengkapnya tentang pola asinkron, lihat Pemrograman asinkron. Untuk contoh tambahan tentang cara menggunakan penangguhan agar tugas latar belakang tidak berhenti lebih awal, lihat sampel tugas latar belakang.

Langkah-langkah berikut diselesaikan di salah satu kelas aplikasi Anda (misalnya, MainPage.xaml.cs).

Catatan

Anda juga dapat membuat fungsi yang didedikasikan untuk mendaftarkan tugas latar belakang—lihat Mendaftarkan tugas latar belakang. Dalam hal ini, alih-alih menggunakan tiga langkah berikutnya, Anda cukup membuat pemicu dan menyediakannya ke fungsi pendaftaran bersama dengan nama tugas, titik masuk tugas, dan (opsional) kondisi.

Daftarkan tugas latar belakang yang akan dijalankan

  1. Cari tahu apakah tugas latar belakang sudah terdaftar dengan melakukan iterasi melalui properti BackgroundTaskRegistration.AllTasks . Langkah ini penting; jika aplikasi Anda tidak memeriksa pendaftaran tugas latar belakang yang ada, aplikasi dapat dengan mudah mendaftarkan tugas beberapa kali, menyebabkan masalah dengan performa dan memaksimalkan waktu CPU tugas yang tersedia sebelum pekerjaan dapat diselesaikan.

Contoh berikut berulang pada properti AllTasks dan mengatur variabel bendera ke true jika tugas sudah terdaftar.

var taskRegistered = false;
var exampleTaskName = "ExampleBackgroundTask";

foreach (var task in BackgroundTaskRegistration.AllTasks)
{
    if (task.Value.Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}
std::wstring exampleTaskName{ L"ExampleBackgroundTask" };

auto allTasks{ Windows::ApplicationModel::Background::BackgroundTaskRegistration::AllTasks() };

bool taskRegistered{ false };
for (auto const& task : allTasks)
{
    if (task.Value().Name() == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }
}

// The code in the next step goes here.
boolean taskRegistered = false;
Platform::String^ exampleTaskName = "ExampleBackgroundTask";

auto iter = BackgroundTaskRegistration::AllTasks->First();
auto hascur = iter->HasCurrent;

while (hascur)
{
    auto cur = iter->Current->Value;

    if(cur->Name == exampleTaskName)
    {
        taskRegistered = true;
        break;
    }

    hascur = iter->MoveNext();
}
  1. Jika tugas latar belakang belum terdaftar, gunakan BackgroundTaskBuilder untuk membuat instans tugas latar belakang Anda. Titik entri tugas harus menjadi nama kelas tugas latar belakang Anda yang diawali oleh namespace.

Pemicu tugas latar belakang mengontrol kapan tugas latar belakang akan berjalan. Untuk daftar pemicu yang mungkin, lihat SystemTrigger.

Misalnya, kode ini membuat tugas latar belakang baru dan mengaturnya untuk dijalankan saat pemicu TimeZoneChanged terjadi:

var builder = new BackgroundTaskBuilder();

builder.Name = exampleTaskName;
builder.TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false));
if (!taskRegistered)
{
    Windows::ApplicationModel::Background::BackgroundTaskBuilder builder;
    builder.Name(exampleTaskName);
    builder.TaskEntryPoint(L"Tasks.ExampleBackgroundTask");
    builder.SetTrigger(Windows::ApplicationModel::Background::SystemTrigger{
        Windows::ApplicationModel::Background::SystemTriggerType::TimeZoneChange, false });
    // The code in the next step goes here.
}
auto builder = ref new BackgroundTaskBuilder();

builder->Name = exampleTaskName;
builder->TaskEntryPoint = "Tasks.ExampleBackgroundTask";
builder->SetTrigger(ref new SystemTrigger(SystemTriggerType::TimeZoneChange, false));
  1. Anda dapat menambahkan kondisi untuk mengontrol kapan tugas Anda akan berjalan setelah peristiwa pemicu terjadi (opsional). Misalnya, jika Anda tidak ingin tugas berjalan hingga pengguna ada, gunakan kondisi UserPresent. Untuk daftar kemungkinan kondisi, lihat SystemConditionType.

Kode sampel berikut menetapkan kondisi yang mengharuskan pengguna untuk hadir:

builder.AddCondition(new SystemCondition(SystemConditionType.UserPresent));
builder.AddCondition(Windows::ApplicationModel::Background::SystemCondition{ Windows::ApplicationModel::Background::SystemConditionType::UserPresent });
// The code in the next step goes here.
builder->AddCondition(ref new SystemCondition(SystemConditionType::UserPresent));
  1. Daftarkan tugas latar belakang dengan memanggil metode Register pada objek BackgroundTaskBuilder . Simpan hasil BackgroundTaskRegistration sehingga dapat digunakan di langkah berikutnya.

Kode berikut mendaftarkan tugas latar belakang dan menyimpan hasilnya:

BackgroundTaskRegistration task = builder.Register();
Windows::ApplicationModel::Background::BackgroundTaskRegistration task{ builder.Register() };
BackgroundTaskRegistration^ task = builder->Register();

Catatan

Aplikasi Windows universal harus memanggil RequestAccessAsync sebelum mendaftarkan salah satu jenis pemicu latar belakang.

Untuk memastikan bahwa aplikasi Universal Windows Anda terus berjalan dengan benar setelah Anda merilis pembaruan, gunakan pemicu ServicingComplete (lihat SystemTriggerType) untuk melakukan perubahan konfigurasi pasca-pembaruan seperti memigrasikan database aplikasi dan mendaftarkan tugas latar belakang. Ini adalah praktik terbaik untuk membatalkan pendaftaran tugas latar belakang yang terkait dengan versi aplikasi sebelumnya (lihat RemoveAccess) dan mendaftarkan tugas latar belakang untuk versi baru aplikasi (lihat RequestAccessAsync) saat ini.

Untuk informasi selengkapnya, lihat Panduan untuk tugas latar belakang.

Menangani penyelesaian tugas latar belakang menggunakan penanganan aktivitas

Anda harus mendaftarkan metode dengan BackgroundTaskCompletedEventHandler, sehingga aplikasi Anda bisa mendapatkan hasil dari tugas latar belakang. Ketika aplikasi diluncurkan atau dilanjutkan, metode yang ditandai akan dipanggil jika tugas latar belakang telah selesai sejak terakhir kali aplikasi berada di latar depan. (Metode OnCompleted akan segera dipanggil jika tugas latar belakang selesai saat aplikasi Anda saat ini berada di latar depan.)

  1. Tulis metode OnCompleted untuk menangani penyelesaian tugas latar belakang. Misalnya, hasil tugas latar belakang dapat menyebabkan pembaruan UI. Jejak metode yang ditampilkan di sini diperlukan untuk metode penanganan aktivitas OnCompleted, meskipun contoh ini tidak menggunakan parameter args .

Contoh kode berikut mengenali penyelesaian tugas latar belakang dan memanggil contoh metode pembaruan UI yang mengambil string pesan.

private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
    var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
    var key = task.TaskId.ToString();
    var message = settings.Values[key].ToString();
    UpdateUI(message);
}
void UpdateUI(winrt::hstring const& message)
{
    MyTextBlock().Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, [=]()
    {
        MyTextBlock().Text(message);
    });
}

void OnCompleted(
    Windows::ApplicationModel::Background::BackgroundTaskRegistration const& sender,
    Windows::ApplicationModel::Background::BackgroundTaskCompletedEventArgs const& /* args */)
{
	// You'll previously have inserted this key into local settings.
    auto settings{ Windows::Storage::ApplicationData::Current().LocalSettings().Values() };
    auto key{ winrt::to_hstring(sender.TaskId()) };
    auto message{ winrt::unbox_value<winrt::hstring>(settings.Lookup(key)) };

    UpdateUI(message);
}
void MainPage::OnCompleted(BackgroundTaskRegistration^ task, BackgroundTaskCompletedEventArgs^ args)
{
    auto settings = ApplicationData::Current->LocalSettings->Values;
    auto key = task->TaskId.ToString();
    auto message = dynamic_cast<String^>(settings->Lookup(key));
    UpdateUI(message);
}

Catatan

Pembaruan UI harus dilakukan secara asinkron, untuk menghindari menahan utas UI. Misalnya, lihat metode UpdateUI di sampel tugas latar belakang.

  1. Kembali ke tempat Anda mendaftarkan tugas latar belakang. Setelah baris kode tersebut, tambahkan objek BackgroundTaskCompletedEventHandler baru. Berikan metode OnCompleted Anda sebagai parameter untuk konstruktor BackgroundTaskCompletedEventHandler .

Kode sampel berikut menambahkan BackgroundTaskCompletedEventHandler ke BackgroundTaskRegistration:

task.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
task.Completed({ this, &MainPage::OnCompleted });
task->Completed += ref new BackgroundTaskCompletedEventHandler(this, &MainPage::OnCompleted);

Nyatakan dalam manifes aplikasi bahwa aplikasi Anda menggunakan tugas latar belakang

Sebelum aplikasi dapat menjalankan tugas latar belakang, Anda harus mendeklarasikan setiap tugas latar belakang dalam manifes aplikasi. Jika aplikasi Anda mencoba mendaftarkan tugas latar belakang dengan pemicu yang tidak tercantum dalam manifes, pendaftaran tugas latar belakang akan gagal dengan kesalahan "kelas runtime tidak terdaftar".

  1. Buka perancang manifes paket dengan membuka file bernama Package.appxmanifest.
  2. Buka tab Deklarasi .
  3. Dari menu drop-down Deklarasi yang Tersedia , pilih Tugas Latar Belakang dan klik Tambahkan.
  4. Pilih kotak centang Peristiwa sistem.
  5. Di kotak teks Titik entri: , masukkan namespace layanan dan nama kelas latar belakang Anda yang untuk contoh ini adalah Tasks.ExampleBackgroundTask.
  6. Tutup perancang paling manfiest.

Elemen Extensions berikut ditambahkan ke file Package.appxmanifest Anda untuk mendaftarkan tugas latar belakang:

<Extensions>
  <Extension Category="windows.backgroundTasks" EntryPoint="Tasks.ExampleBackgroundTask">
    <BackgroundTasks>
      <Task Type="systemEvent" />
    </BackgroundTasks>
  </Extension>
</Extensions>

Ringkasan dan langkah berikutnya

Anda sekarang harus memahami dasar-dasar cara menulis kelas tugas latar belakang, cara mendaftarkan tugas latar belakang dari dalam aplikasi Anda, dan cara membuat aplikasi Anda mengenali saat tugas latar belakang selesai. Anda juga harus memahami cara memperbarui manifes aplikasi sehingga aplikasi Anda dapat berhasil mendaftarkan tugas latar belakang.

Catatan

Unduh sampel tugas latar belakang untuk melihat contoh kode serupa dalam konteks aplikasi UWP yang lengkap dan kuat yang menggunakan tugas latar belakang.

Lihat topik terkait berikut untuk referensi API, panduan konseptual tugas latar belakang, dan instruksi yang lebih rinci untuk menulis aplikasi yang menggunakan tugas latar belakang.

Topik instruksi tugas latar belakang terperinci

Panduan tugas latar belakang

Referensi API Tugas Latar Belakang