In meinem früheren Beitrag (Funktionalität von Apps im Hintergrund) habe ich das Hintergrundmodell von Windows 8 erläutert und erklärt, wie Ihre Apps Aufgaben auch dann energieeffizient ausführen können, wenn sie nicht auf dem Bildschirm angezeigt werden. In diesem Beitrag werde ich Hintergrundaufgaben thematisieren und beschreiben, wie Apps auch in angehaltenem Zustand im Hintergrund Code ausführen können. Ich werde anhand von zwei häufigen Szenarios mit Codebeispielen darstellen, wie Sie eigenen App-Code im Hintergrund ausführen können – z. B. das Abrufen von POP-E-Mails in 15-Minuten-Intervallen mit Apps, die auf dem Sperrbildschirm ausgeführt werden können, und das Ausführen von App-Aufgaben im Hintergrund, wenn das Gerät an eine Steckdose angeschlossen ist.

Einführung

Da Auslöser von Hintergrundaufgaben für verschiedene Szenarios und Anwendungen entworfen werden, müssen auch jeweils unterschiedliche Anforderungen und Einschränkungen bzgl. des Ressourcenmanagements beachtet werden. Einige Auslöser von Hintergrundaufgaben wurden für Apps entwickelt, die kontinuierlich aktualisiert werden müssen (z. B. E-Mail- oder VoIP-Apps). Andere wurden für seltenere Verwendung entworfen (z. B. das Ausführen von Wartungsaufgaben, wenn das Gerät an eine Steckdose angeschlossen ist, oder bei Änderung bestimmter Systembedingungen). Die Apps, die kontinuierlich aktualisiert werden müssen, müssen auf dem Sperrbildschirm angezeigt werden. Hier können maximal sieben Apps angezeigt werden. Darauf werde ich in diesem Beitrag noch ausführlicher eingehen. Im Gegensatz dazu können Apps, die nur in bestimmten Situationen Aufgaben ausführen müssen, den Wartungsauslöser beim Anschluss an eine Steckdose oder bestimmte Systemauslöser verwenden. Die App muss nicht auf dem Sperrbildschirm platziert werden, um diese Auslöser verwenden zu können. Für Apps auf dem Sperrbildschirm gelten weniger strenge Ressourceneinschränkungen, da sie häufiger ausgeführt werden müssen. (Darum wurde die Anzahl möglicher Apps auf dem Sperrbildschirm begrenzt und die Entscheidung dem Benutzer überlassen.) Dazu später mehr.

Wenn Sie lediglich die Inhalte einer App aktualisieren möchten, müssen Sie keine Hintergrundaufgaben ausführen. Sie können jederzeit Live-Kacheln oder geplante Benachrichtigungen verwenden. Näheres dazu finden Sie in dem Beitrag Erstellen einer benutzerfreundlichen Kachel. Wenden wir uns nun dem Ausführen von Code zu.

Arbeiten im Hintergrund, wenn das Gerät an eine Steckdose angeschlossen ist

Wie bereits in meinem früheren Beitrag erläutert, müssen Apps manchmal eigenen Code ausführen, um Hintergrundfunktionen zur Verfügung zu stellen. Nehmen wir z. B. an, Sie möchten alle Fotos der Bildbibliothek der App-Datenbank hinzufügen oder anderweitig verarbeiten (z. B. Miniaturansichten erstellen). Sie können diese Aufgabe ausführen, wenn die App im Vordergrund ausgeführt und vom Benutzer verwendet wird. Sie können auch Hintergrundaufgaben mit einem Wartungsauslöser verwenden, der nur dann im Hintergrund ausgeführt wird, wenn das Gerät an eine Steckdose angeschlossen ist. Der Wartungsauslöser ist frei verfügbar, und die App muss nicht auf dem Sperrbildschirm platziert werden. Der Vorteil einer Hintergrundaufgabe mit Wartungsauslöser ist, dass dieser Vorgang keinesfalls die Gerätenutzung beeinträchtigt und nur ausgeführt wird, wenn das Gerät an eine Steckdose angeschlossen ist. Die Akkukapazität wird also nicht beansprucht.

In diesem Codebeispiel wird von der Wartungshintergrundaufgabe die ProcessPictures-Klasse aufgerufen, um die Dateien bei Aufgabenausführung zu verarbeiten. Die Aufgabe wird in achtstündigen Intervallen ausgeführt, um eventuell zu verarbeitende Dateien zu ermitteln. Die Hintergrundaufgabe wird außerdem für einen Abbruchhandler registriert, da Wartungshintergrundaufgaben abgebrochen werden, wenn das Gerät zum Akkubetrieb wechselt. Der Abbruchhandler beendet die Verarbeitung der Dateien. Die App wird von Windows beendet, wenn sie nicht innerhalb von fünf Sekunden vom Abbruchhandler freigegeben wird. Bei diesen Codebeispielen wird Erfahrung mit Hintergrundaufgaben und Auslöserklassen vorausgesetzt. Weitere Informationen zu diesen Klassen finden Sie in der Namespace-Dokumentation Windows.ApplicationModel.Background im Entwicklungscenter.

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();
});
});
                   

In diesem Codebeispiel wird das Registrieren der Wartungshintergrundaufgabe über die Haupt-App veranschaulicht. Diese Hintergrundaufgabe wird alle acht Stunden gestartet, um alle Bilder zu verarbeiten, die sich in der Bibliothek für Bilder und Dokumente befinden. Wenn dieser Vorgang nicht mehr erforderlich ist, können Sie die Registrierung der Hintergrundaufgabe mithilfe der Unregister-Methode der IBackgroundTaskRegistration-Klasse aufheben.

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;
}

Hintergrundaufgaben müssen im App-Manifest deklariert werden. Öffnen Sie zunächst das App-Manifest in Visual Studio. Fügen Sie anschließend auf der Registerkarte „Deklarationen“ mithilfe des Dropdownmenüs die Deklarationen für die Hintergrundaufgaben hinzu. Wählen Sie den entsprechenden Aufgabentyp aus, und geben Sie den Einstiegspunkt (Name der Klasse der Hintergrundaufgabe) oder, falls Sie eine JavaScript-Hintergrundaufgabe verwenden, die Startseite an.

Deklarationen von Hintergrundaufgaben im Manifest 
Abbildung 1 – Deklarationen von Hintergrundaufgaben im Manifest

Wenn Sie den Inhalt des Manifests anzeigen möchten, klicken Sie mit der rechten Maustaste auf das Manifest, und wählen Sie „Code anzeigen“ aus. Beachten Sie, dass die Wartungsaufgabe nur im systemeigenen Host („backgroundTaskHost.exe“ bzw. „wwahost.exe“ für JavaScript) ausgeführt werden kann. Daher können Sie kein Executable-Attribut festlegen. Der Aufgabentyp des Wartungsauslösers lautet systemEvent, wie aus diesem Manifestausschnitt ersichtlich.

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

In JavaScript wird EntryPoint durch ein StartPage-Attribut ersetzt.

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

Weitere Informationen zur Verwendung von Hintergrundaufgaben finden Sie im Whitepaper Introduction to Background Tasks, Informationen zur API-Verwendung finden Sie im Entwicklungscenter.

Herunterladen von POP-E-Mail in 15-Minuten-Intervallen

In diesem Beispiel ist es erforderlich, dass die App vorhersagbar und regelmäßig im Hintergrund ausgeführt wird. Dies können Sie erreichen, indem Sie die App auf dem Sperrbildschirm platzieren.

Mithilfe von Hintergrundaufgaben werden Apps auch dann aktualisiert, wenn der Benutzer das Windows 8-Gerät nicht verwendet. Der Benutzer kann Apps Berechtigungen erteilen, auf dem Sperrbildschirm ausgeführt zu werden, und so steuern, welche Apps Hintergrundaufgaben verwenden dürfen. Dies ist nur konsequent: Denn der Sperrbildschirm ist dazu gedacht, Benutzern Informationen zu ihren Apps zur Verfügung zu stellen, ohne dass das Windows 8-Gerät entsperrt werden muss. Dabei schwingt die Tür in beide Richtungen: Die App kann diese Hintergrundaufgaben nur verwenden, wenn sie auf dem Sperrbildschirm ausgeführt wird. Sie kann jedoch nur dann auf dem Sperrbildschirm ausgeführt werden, wenn sie das Verwenden dieser Hintergrundaufgaben anfordert.

background2_img2

Abbildung 2 – Personalisierungsfunktionen für den Sperrbildschirm und Apps, die auf dem Sperrbildschirm ausgeführt werden können

Da nur eine kleine Anzahl an Apps auf dem Sperrbildschirm ausgeführt werden kann, muss das Anzeigen Ihrer App auf dem Sperrbildschirm dem Benutzer deutliche Vorteile bieten. Andernfalls wird sie voraussichtlich rasch vom Sperrbildschirm entfernt, um andere Apps hinzufügen zu können. Apps dieser Kategorie sind z. B. Kommunikations-Apps, z. B. eine E-Mail-App, die die Anzahl ungelesener Nachrichten anzeigt, eine Kalender-App mit bevorstehenden Terminen oder eine Messaging-App, die die Anzahl der nicht gelesenen Sofortnachrichten anzeigt. Weitere Informationen zum Sperrbildschirm und zur Steigerung der Attraktivität der Sperrbildschirmfunktionen von Apps finden Sie im Entwicklungscenter.

Verwenden eines Zeitauslösers, um die E-Mails alle 15 Minuten herunterzuladen

Mit diesem Beispiel wird aufgezeigt, wie eine Zeitauslöser-Hintergrundaufgabe registriert wird, der mithilfe der Klasse BackgroundTaskBuilder alle 15 Minuten ausgeführt wird, sofern eine Internetverbindung vorhanden ist. Wenn keine Internetverbindung vorhanden ist, wird die Hintergrundaufgabe nicht ausgeführt. Die Ausführung erfolgt erst, wenn eine Internetverbindung verfügbar ist. Hierbei handelt es sich um ein weiteres hilfreiches Feature der Hintergrundaufgaben, mit dem unnötige Arbeiten vermieden und die Lebensdauer des Akkus verlängert werden. Ohne diese Bedingung müsste der Anwendungscode ausgeführt werden, erkennen, dass keine Netzwerkverbindung besteht, und mit einem Fehler beendet werden, da die E-Mails nicht heruntergeladen werden können. Die E-Mails werden unabhängig davon heruntergeladen, ob die Anwendung im Hintergrund ausgeführt wird oder nicht. Sie werden auch heruntergeladen, wenn sich das Gerät im Verbindungsstandbymodus befindet.

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;
}

Der Zeitauslöser ist, wie bereits beschrieben, nur für Apps auf dem Sperrbildschirm verfügbar. Um die Platzierung auf dem Sperrbildschirm programmgesteuert anzufordern, muss die Klasse „BackgroundExecutionManager“ verwendet werden. Die Hintergrundaufgaben werden nur ausgeführt, wenn der Benutzer Ihre App nicht auf dem Sperrbildschirm platziert. Gegebenenfalls müssen Sie auf eine Hintergrundaufgabe zurückgreifen, die keinen Sperrbildschirm erfordert, oder die Aufgabe ausführen, wenn der Benutzer die App verwendet. Benutzer werden von System nur einmal aufgefordert, die App zum Sperrbildschirm hinzuzufügen. Wenn die Benutzer dies ablehnen und die App zu einem späteren Zeitpunkt hinzufügen möchten, muss dies manuell erfolgen.

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;
});
}

Dieses Codebeispiel stellt die Haupthintergrundaufgabe dar, mit der die E-Mails alle 15 Minuten heruntergeladen werden. Hier finden Sie keine ausführlichen Beschreibungen des Aktualisierens der Kachel und der Infoanzeiger Ihrer App, da dies bereits im Blogbeitrag Erstellen einer benutzerfreundlichen Kachel erläutert wurde.

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();

Um Ihre App dem Sperrbildschirm hinzufügen zu können, muss auf der Registerkarte für die Anwendungsbenutzeroberfläche der Sperrbildschirm-Benachrichtigungstyp angegeben werden.


Abbildung 3 – Deklarationen von Hintergrundaufgaben im Manifest

Dies ist ein (vom Assistenten erzeugter) Codeausschnitt des Manifests einer App, die auf dem Sperrbildschirm platziert werden muss und auf diesem Infoanzeiger und Popups anzeigt. Die Zeitauslöseraufgabe kann nur im systemeigenen Host („backgroundTaskHost.exe“ bzw. „wwahost.exe“ für JavaScript) ausgeführt werden. Daher können Sie kein Executable-Attribut festlegen. Wie aus dem Manifest zu ersehen ist, handelt es sich beim Aufgabentyp um „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>

In JavaScript wird EntryPoint durch ein StartPage-Attribut ersetzt.

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

 

Erweiterte Szenarien

Sie können funktionsreichere VoIP-, IM- oder Push-E-Mail-Apps mithilfe weiterer Hintergrundaufgabenauslöser wie z. B. „Control Channel“ oder „Push Notification“ erstellen. Deren Verwendung geht jedoch über diesen Beitrag hinaus. Weitere Informationen finden Sie im Whitepaper Background Networking.

Ressourcenverwaltung für Hintergrundaufgaben

Wie bereits erwähnt, wurden die Hintergrundaufgaben im Sinne einer Energieeffizienz entwickelt. Daher gelten für diese Beschränkungen für die CPU- und Netzwerkverwendung. Dadurch wird verhindert, dass eine App im Hintergrund den Akku des Geräts belastet, ohne dass dies vom Benutzer bemerkt wird. Wenn eine App aktiv ist, und der Benutzer diese im Vordergrund verwendet, gelten für deren Hintergrundaufgaben keine CPU- oder Netzwerkressourcenbeschränkungen.

CPU-Ressourcenbeschränkungen

Alle Apps auf dem Sperrbildschirm erhalten alle 15 Minuten zwei Sekunden CPU-Zeit, die von allen Hintergrundaufgaben der Apps verwendet werden können. Am Ende der 15 Minuten erhalten alle Apps auf dem Sperrbildschirm weitere zwei Sekunden CPU-Zeit für deren Hintergrundaufgaben. Jegliche in diesem 15-Minuten-Intervall nicht genutzten CPU-Zeiten verfallen und können von der App nicht angesammelt werden. Alle Apps, die nicht auf dem Sperrbildschirm platziert wurden, erhalten alle zwei Stunden eine Sekunde CPU-Zeit. Wenn eine App die gesamte verfügbare CPU-Zeit verwendet, werden deren Hintergrundaufgaben angehalten, bis das CPU-Kontingent beim nächsten Aktualisieren der CPU-Kontingente wieder aufgestockt wird.

Die CPU-Nutzungsdauer bezieht sich auf den tatsächlich von der App verwendeten CPU-Betrag, nicht jedoch auf die Wanduhrzeit der Hintergrundaufgabe. Wenn die Hintergrundaufgabe im Code auf die Antwort des Remoteservers wartet und dabei keine CPU-Leistung verwendet, wird diese Wartezeit nicht mit dem CPU-Kontingent verrechnet.

CPU-Ressourcenbeschränkungen für Hintergrundaufgaben

 

CPU-Ressourcenkontingente

Aktualisierungszeitraum

Sperrbildschirm-fähige App

2 CPU-Sekunden

15 Minuten

Nicht Sperrbildschirm-fähige App

1 CPU-Sekunde

2 Stunden

Netzwerkressourcenbeschränkungen

Die Netzwerkverwendung kann sich erheblich auf den Geräteakku auswirken. Daher wird diese beim Ausführen von Hintergrundaufgaben beschränkt. Wenn ein Gerät jedoch jedoch an eine Steckdose angeschlossen ist, unterliegen die Hintergrundaufgaben keiner Netzwerkbeschränkung. Die CPU-Nutzung einer Hintergrundaufgabe unterliegt auch dann einer Ressourcenbeschränkung, wenn das Gerät an eine Steckdose angeschlossen ist.

In der folgenden Tabelle finden Sie den Netzwerkdatendurchsatz eines ressourcenbeschränkten WiFi-Netzwerks. Hierbei wird von minimalen Interferenzen ausgegangen.

Durchschnittlicher Durchsatz der Netzwerkschnittstelle

Datendurchsatz in Megabyte (MB)
für Sperrbildschirm-fähige Apps

Datendurchsatz in MB für nicht Sperrbildschirm-fähige Apps

Alle 15 Minuten

Pro Tag

Pro Tag

10 Mbit/s

1.875

180

30

 

Globaler Pool

Diese festen Ressourcenbeschränkungen können selbst im Rahmen der den einzelnen Apps zugewiesenen Kontingenten unzureichend sein. Für diesen Fall ist ein gemeinsamer globaler Pool vorhanden, aus dem die Anwendungen CPU- und Netzwerkressourcen anfordern können.

Ausführliche Informationen zu den Hintergrundaufgaben, dem globalen Pool, den Ressourcenverwaltungsbeschränkungen und den Best Practices finden Sie im Whitepaper Introduction to Background Tasks. Dieses enthält zudem ein Beispielprojekt mit Quellcode.

Zusammenfassung

Die Antwort auf die Frage „Kann meine App Aufgaben ausführen, wenn diese nicht angezeigt wird?“ lautet eindeutig „Ja“. Mit dem Hintergrundmodell von Windows 8 kann Ihre App wichtige Endbenutzerszenarien wie z. B. das Herunterladen von Dateien, das Wiedergeben von Audiodateien, das Aktualisieren von E-Mails im Hintergrund oder das Durchführen von Wartungsaufgaben ausführen, wenn das Gerät an eine Steckdose angeschlossen ist. Da diese Aktivitäten von der Plattform natürlich genau überwacht werden, wirken sich diese Hintergrundaufgaben nur minimal auf die Reaktionsfähigkeit der App im Vordergrund oder die Lebensdauer des Gerätakkus aus.

Ausführlichere technische Informationen zum Hintergrundmodell von Windows 8 finden Sie im Entwicklungscenter und in den verschiedenen Whitepapers. Wenn Sie Fragen haben, können Sie diese gerne hier in den Kommentaren stellen. Wir werden uns um bestmögliche Antworten bemühen.

– Hari Pulapaka, Program Manager, Windows.

Dank an Jake Sabulsky, Johnny Bregar, Kyle Beck und Suhail Khalid für ihre Beiträge. Dies gilt auch für das wertvolle Feedback u. a. von Alexander Corradini, Arun Kishan, Ben Srour, Ian LeGrow, Jamie Schwartz und John Sheehan.

Ressourcen

Link

Typ

Highlights

Introduction to Background Tasks

Whitepaper

Bietet eine Einführung zu den Hintergrundaufgaben

Background Model API Namespace

Dokumentationen

API-Namespace des Hintergrundmodells

Beispielprojekt für Hintergrundaufgaben

Beispielprojekt

Zeigt die Verwendung von Hintergrundaufgaben

Lock Screen Overview

Konzeptdokumentation

Erläutert den Sperrbildschirm und die entsprechenden Best Practices

Background Networking

Whitepaper

Zeigt, wie funktionsreichere Apps z. B. für VoIP und IM mithilfe von Hintergrundaufgaben entwickelt werden

Erstellen einer benutzerfreundlichen Kachel

Blogbeitrag

Zeigt, wie benutzerfreundliche Kacheln erstellt werden