In den nächsten Beiträgen von uns Jetpack DataStore-ReiheWir werden einige zusätzliche Konzepte behandeln, um zu verstehen, wie der DataStore mit anderen APIs kommuniziert, sodass Ihnen alles zur Verfügung steht, um ihn zu verwenden Produktionsumfeld. In diesem Beitrag konzentrieren wir uns besonders auf das Arbeiten Synchronbetrieb mit DataStore. Wir verweisen auf Einstellungen Codelabfür Codebeispiele.
In dieser Serie haben wir den DataStore erwähnt vollständig asynchrone APIdie sich aus der internen Verwendung ergeben Kotlin Korutine und Flow. Um potenzielle ANRs und Verzögerungen der Benutzeroberfläche zu verhindern, wenn schwierige I/O-Operationen auf UI-Threads ausgeführt werden, DataStore bietet keine gebrauchsfertige synchrone Unterstützung. Der DataStore speichert seinen Datensatz in einer Datei und führt alle Datenoperationen unter der Haube durch Dispatchers.IO, Sofern nicht anders angegeben, bleibt Ihr UI-Thread entsperrt. Diese API-Struktur ist eine von Hauptvorteile DataStore im Vergleich zum Vorgänger SharedPreferences und wie man den DataStore in den meisten Fällen verwendet.
Wenn Sie jedoch feststellen, dass Ihr Code erfordert, dass Sie synchron mit dem DataStore arbeiten, sei es, weil Sie von einer anderen API abhängig sind, die im Hauptthread ausgeführt wird, oder weil Ihr aktuelles Setup erfordert, dass Sie einige dauerhafte Werte für UI-Einstellungen abrufen, können Sie dies tun benutzen runBlocking() Programmierer zum Lesen von DataStore synchron. Dieser Wille blockiert den Anruf-Thread bis DataStore zurückkehrt:
Wenn Sie sich in einer Situation befinden, in der Sie diesen Ansatz verwenden müssen, verbringen Sie einige Zeit damit, herauszufinden, ob dies der Fall ist unbedingt notwendig, um den Hauptthread zu blockieren. Überlegen Sie, wie Sie die Lieferung nutzen könnten Asynchrone DataStore-Alternative oder refaktorisieren Sie Ihren aktuellen Code, um dies zu vermeiden runBlocking()zum Beispiel durch asynchrones Laden von Daten im Voraus:
Wenn dies nicht möglich ist, stellen Sie sicher, dass Sie alle potenziellen UI-Jank-Szenarien abdecken, indem Sie Fehler behandeln. Stornierungen und Fristen oder einige nette visuelle Elemente, um die Benutzererfahrung so einfach wie möglich zu machen.
Wir haben behandelt, wie es durchgeführt wird Synchronbetrieb mit DataStore. Obwohl dies kein empfohlener Ansatz für den DataStore ist, können Sie ihn verwenden, wenn Ihre aktuelle Einstellung synchrone Aufrufe erfordert .runBlocking() kombiniert mit .first() Operator.
Begleiten Sie uns für den nächsten Beitrag in der Serie, in dem wir untersuchen, wie es geht DataStore-zu-DataStore-Migration.
Eine der Herausforderungen der mobilen Entwicklung ist der Umgang mit Integrationen von Drittanbietern und insbesondere das automatische Testen solcher Integrationen. Push-Messaging mit FCM ist ein solcher Fall, in dem die Auswirkungen von Integrationsstörungen hoch sein können, insbesondere während einer Kampagne oder der Ausstellung einer Notfallkorrektur. Sehen wir uns an, wie wir Tests vollständig automatisieren können, um sicherzustellen, dass unsere FCM-Integrationen nie wieder fehlschlagen.
Instrumenteller Android-Test, der den Push-Flow bestätigt
Firebase Cloud Messaging ist zum De-facto-Standard für Push-Messaging für Android-Anwendungen geworden. Es ist eine plattformübergreifende Messaging-Lösung, mit der Sie Nachrichten zuverlässig und kostenlos versenden können.
Der gesamte Ablauf von Push-Benachrichtigungen wird erklärt Hier.
Die Anwendung erhält über das Firebase SDK ein Push-Token vom FCM-Back-End.
Die Anwendung überträgt dieses Token an den Anwendungsserver.
Die Serveranwendung löst eine Push-Nachricht mit dem geladenen Token und der HTTP-Anforderung an das FCM-Backend aus.
Eine Push-Nachricht erreicht die Anwendung und löst die gewünschte Aktion aus.
Testen des Push-Nachrichtenflusses
Der Durchfluss umfasst mehrere bewegliche Teile, und das Testen kann schwierig und zeitaufwändig sein. Noch wichtiger ist, dass es lange dauern kann, bis eine der Integrationen fehlschlägt, bis dies erkannt wird, und es kann im ungünstigsten Moment passieren, wenn Sie Ihren Benutzern tatsächlich Push-Nachrichten senden möchten.
Wenn wir den Nachrichtenfluss von Ende zu Ende zuverlässig testen wollen, müssen wir dafür mehrere Probleme lösen.
Synchronisieren Sie das Senden und Empfangen von Push-Nachrichten.
Haben Sie ein Gerät, das ein FCM-Token empfängt.
Verwenden Sie einen Token mit FCM-Hintergrund, um eine Push-Nachricht auszulösen.
Lassen Sie den Test auf die Push-Nachricht warten.
Stellen Sie sicher, dass die Anwendung die richtige Push-Nachricht erhalten hat.
Problem 1 kann gelöst werden, indem der instrumentelle Test der Anwendung in den Hintergrund der Anwendung gestellt wird und mit dem FCM-Hintergrund kommuniziert wird. Auf diese Weise vermeiden wir den zusätzlichen beweglichen Teil des Anwendungshintergrunds und integrieren die vollständige Flusskontrolle in unseren Test.
Instrumenteller Android-Test, der den Push-Flow bestätigt
Problem 2 – die Notwendigkeit eines echten Geräte-Tokens kann durch die Verwendung von gelöst werden Firebase-Testlabor physische Geräte über Gcloud-CLI ich Gradle-Widget Tests durchzuführen. Ein instrumentiertes Testpaket, das auf einem tatsächlichen Gerät ausgeführt wird, verfügt unmittelbar nach dem Start der App über ein Push-Token, und wir können das Token direkt in unserem Testcode verwenden.
Darauf folgt Fehlerbehebung 3 – Ausführen eines Push durch das FCM-Backend. Alles, was wir dafür brauchen, ist ein Push-Token und eine einfache Nachrüstung PushServerClientwas umsetzen wird FCM-HTTP-Protokoll. Dann müssen wir den FCM-Autorisierungsschlüssel in unserem Gerätetest bestehen, was durch Weiterleitung von a erfolgen kann Instrumentelles Testargument auf das Gerät über gcloud Parameter von Umgebungsvariablen er fügte hinzu Widget Gradle.
Es kann einige Zeit dauern, bis das FCM-Backend eine Push-Nachricht sendet und die Anwendung sie im Testlabor empfängt. Wir müssen sicherstellen, dass der Test nicht weiter behauptet, bevor die Nachricht eintrifft, um sicherzustellen, dass der Test zuverlässig ist.
Aus der abschließenden Behauptung können wir ersehen, dass der gesamte Kurs wie erwartet verlaufen ist. Dieser Test bestätigt, dass die Anwendung ausgeführt wird Einstellungsfenster bevor Sie zu navigieren über den Bildschirm nachdem eine Push-Nachricht mit dieser tiefen Verbindung eintrifft. (Video vom Test)
Wir haben jetzt einen vollautomatisierten Test, der den Ablauf des Empfangs von Push-Nachrichten aus dem FCM-Hintergrund durchläuft und überprüft, ob die Anwendung sie ordnungsgemäß verarbeitet.
Die durch eine Push-Nachricht ausgelöste Aktion hängt weitgehend von Ihrer Anwendung ab, sodass die Art und Weise, wie Sie überprüfen, ob sie korrekt behandelt werden, unterschiedlich sein wird. Hier ist entscheidend, dass die Push-Nachricht ankommt und die Anwendung entsprechend darauf reagiert.
Unzuverlässigkeit ist immer ein Problem, wenn es um Tests geht, die sich wie dieses in ein Live-Backend eines Drittanbieters integrieren lassen. Das Referenz-Repo wurde implementiert metrischer Testdie uns eine gute Antwort auf diese Frage geben kann.
Die Tests wurden zuverlässig einen Monat lang auf 2 verschiedenen Firebase Test Lab Geräten mit durchgeführt 260 erfolgreiche Läufe in Folge.
Daten zur Leistung von Push-Messaging-Tests 260 von 260 haben bestanden
Somit ist die Antwort klar – Ja, der Test ist zuverlässig und funktioniert derzeit gut mit dem P90 1,6 Sek und weniger als 0,6 s für die mittlere Zeit. Dies bedeutet, dass die Dauer mit anderen Espresso UI-Tests vergleichbar ist und sich gut in jedes Testpaket einfügen lässt.
Der P90-Push-Messaging-Test beträgt 1,627 Sekunden
Das Testen der Automatisierung Ihrer Push-Nachrichten-Szenarien kann Ihnen viele Risiken zu geringen Kosten ersparen und Ihre Push-Nachrichten-Integration zum Vergnügen für eine sichere Wiederholung machen. Ingenieure können sogar Tests verwenden, um neue Push-Szenarien zu testen und die TDD-Form ohne die mühsamen manuellen HTTP-Anforderungen des FCM-Backends zu erreichen.
Wie testen Sie Ihre Drittanbieter-Integrationen? Automatisieren Sie Tests? Lass es mich in den Kommentaren wissen.
In den nächsten Beiträgen von uns Jetpack DataStore-ReiheWir behandeln einige zusätzliche Konzepte, um zu verstehen, wie der DataStore mit anderen APIs interagiert, sodass Sie alles zur Verfügung haben, um ihn zu verwenden Produktionsumfeld. In diesem Beitrag konzentrieren wir uns auf Kotlin-Serialisierung. Wir verweisen auf Einstellungen ich Proto Codelabs über diesen Beitrag für Codebeispiele.
In unseren vorherigen Beiträgen haben wir geschrieben, wie Einstellungen ich Proto DataStore-Ansatz zur Strukturierung und Serialisierung Ihrer persistenten Daten: Vorteile von Proto typisierte Objekte unterstützt Protokollpuffer, während Einstellungen verwendet Schlüssel/Wert-Paare wie unsere Datenanzeige, ähnlich wie SharedPreferences. Unter der Haube, Beide Implementierungen speichern Daten unter Verwendung von Protokollpuffern auf der Festplatte in einer Datei. Aber der DataStore ermöglicht es Ihnen auch, dies anzupassen und auch Datenklassen zu verwenden Kotlin-Serialisierungdir geben Art des Sicherheitsvorteils Proto DataStore, aber ohne die Notwendigkeit, Protobuffs zu verwenden. Sehen wir uns an, wie die Serialisierung standardmäßig für jeden dieser Ansätze funktioniert:
DataStore-Serialisierungsoptionen
Preferences DataStore vereinfacht die Arbeit mit Protobuffs durch Hinzufügen zusätzliche Schicht zusätzlich zu seiner geringen Proto-Implementierung. Auf diese Weise erhalten Sie es viele Vorteile der Arbeit mit DataStoreaber mit a SharedPreferences-als Mittel zur Strukturierung von Daten verwenden Schlüssel/Wert-Paare.
Wenn wir uns die Preferences API ansehen PreferencesSerializer und unser benutzerdefiniertes ProtoUserPreferencesSerializerSie werden feststellen, dass sie meistens dasselbe tun. PreferencesSerializer es hat nur einen zusätzlichen Transformationsschritt Schlüssel/Wert-Paare in Protobuffs und umgekehrt:
Implementierung von DataStore mit Kotlin-Serialisierung
Wenn Sie verwenden möchten Kotlin-Serialisierung Um Ihre Daten zu strukturieren, müssen Sie lediglich a definieren eine vollständig unveränderliche Datenklasse und einen DataStore implementieren Serializer.
DataStore verlässt sich auf equals ich hashCode die für Datenklassen automatisch generiert werden. Es werden auch Datenklassen generiert toString ich copy Funktionen, die zum Debuggen und Aktualisieren von Daten nützlich sind:
🚨 Das ist sehr wichtig Stellen Sie sicher, dass Ihre Klasse unveränderlich ist seit DataStore ist nicht mit Variablentypen kompatibel. Die Verwendung von Variablentypen mit dem DataStore führt dazu Fehler aufgrund inkonsistenter Daten und Rennbedingungen. Datenklassen Sie sind nicht unbedingt standardmäßig unveränderlichStellen Sie also sicher, dass Sie überall wave anstelle von vars verwenden:
Arrays sind variabel, also sollten sie nicht ausgesetzt werden. Auch wenn wir es nur zum Lesen verwenden List als Mitglied unserer Datenklasse ist es immer noch variabel. Stattdessen sollten Sie erwägen, es zu verwenden unveränderliche / dauerhafte Sammlungen:
Die Verwendung von Variablentypen als Mitglied Ihrer Datenklasse macht sie änderbar. Stattdessen sollten Sie dafür sorgen alles Mitglieder sind unveränderliche Typen.
Kotlin unterstützt die Serialisierungmehrere Formateeinschließlich JSON und Protokollpuffer. In diesem Beispiel fahren wir mit JSON fort.
Um Ihre Datenklasse in JSON mithilfe der Kotlin-Serialisierung zu lesen und zu schreiben, müssen Sie Ihre Datenklasse mit markieren @Serializable und überwältigen Serializer’swriteTo() ich readFrom(). Hier ein Beispiel mit UserPreferences:
⚠️ Grundstücke sind nicht sicher mit DataStore verwenden, da sich das Datenformat zwischen Android-Versionen ändern kann.
Gehen Sie die neu erstellten durch UserPreferencesSerializer im DataStore, wenn Sie es erstellen:
Das Auslesen der Daten sieht genauso aus wie bei Protobuffs:
Sie können die generierte verwenden .copy() Datenaktualisierungsfunktion:
Verwenden von DataStore mit Kotlin-Serialisierung und Datenklassen kann den Standard senken und Ihren Code vereinfachenSie müssen jedoch darauf achten, es nicht einzuführen Fehler durch Variabilität. Sie müssen lediglich Ihre Datenklasse definieren und einen Serializer implementieren.
Wir deckten ab Kotlin-Serialisierung und die notwendigen Schritte zur Verwendung Persistente DataStore-Daten strukturieren – Verwenden von vollständig unveränderlichen Datenklassen und Schreiben in JSON mit@Serializable Beachten Sie, überwältigend unsere Serializer’swriteTo() ich readFrom() und schließlich die Weiterleitung an unsere DataStore-Instanz.
Begleiten Sie uns für den nächsten Beitrag in unserer Serie, in dem wir untersuchen, wie es geht Synchronbetrieb mit DataStore.
Eine Bibliothek, die Janko in der realen Welt verfolgt
Jank (Substantiv): Schlechte Anwendungsleistung, die zu fehlenden Frames, unterbrochenen UI-Bewegungen und schlechter Benutzererfahrung führen kann. Siehe „Unzufriedene Benutzer“.
Das Debuggen der Leistung ist … schwierig. Es ist oft nicht klar, wo man anfangen soll, welche Tools zu verwenden sind, welche Probleme Benutzer haben oder wie sich diese Probleme auf realen Geräten manifestieren.
Das Android-Team hat in den letzten Jahren mehr Debugging-Tools für verschiedene Teile des Problems bereitgestellt, angefangen bei der Analyse Startleistung beim Testen bestimmte Codepfade insbesondere auf das Testen und Optimieren Anwendungsfälle zu visuelle Profiler in der IDE. All dies dient zum Testen der Entwicklungszeit, um Ihnen bei der Fehlerbehebung und Behebung von Problemen zu helfen, die Sie lokal sehen.
Inzwischen sind beide Google Play Android-Vitals ich Firebase Bieten Sie Dashboards an, in denen Entwickler sehen können, wie ihre Apps auf Benutzergeräten im Feld funktionieren.
Es ist jedoch schwierig zu wissen, wie Sie Probleme finden können, die Ihre Anwendung in realen Situationen haben kann, insbesondere Probleme, die auf Benutzergeräten auftreten, und nicht nur Situationen, die Sie auf dieser praktischen Entwicklungsmaschine sehen, die Sie bequem von Ihrem Stuhl aus verwenden. Leistungssteuerungsfelder sind hilfreich, bieten jedoch nicht unbedingt die Detailgenauigkeit, die Sie benötigen, um zu wissen, was passiert ist, wenn Ihre Benutzer Probleme hatten.
Eingeben JankStats: Die erste AndroidX-Bibliothek, die speziell für die Instrumentierung und Meldung von Leistungsproblemen Ihrer App auf Benutzergeräten entwickelt wurde.
JankStats ist eine relativ kleine API mit im Wesentlichen drei Zielen: Erfassen von Leistungsinformationen pro Frame, Ausführen Ihrer Anwendung auf Benutzergeräten (nicht nur Entwicklungsgeräten) und Aktivieren von Instrumentierung und Berichten darüber, was in Ihrer Anwendung passiert, wenn es Leistungsprobleme gibt.
Die Android-Plattform bietet bereits Möglichkeiten, Frame-Performance-Daten abzurufen. Beispielsweise können Sie FrameMetrics ab API 24 verwenden, und wir haben es in neueren Versionen hinzugefügt, um noch mehr Informationen bereitzustellen. Wenn Sie frühere Versionen verwenden, gibt es verschiedene Ansätze, um weniger genaue, aber dennoch nützliche Wetterinformationen zu erhalten.
Wenn Sie also möchten, dass Ihre eigene Frame-Dauer-Logik in allen Editionen funktioniert, müssen Sie diese verschiedenen Mechanismen in allen Versionen der API implementieren. Oder Sie können die einzigartige JankStats-API verwenden, die für Sie funktioniert … zusätzlich zu den zusätzlichen Funktionen oben (lesen Sie weiter!).
JankStats vereinfacht dies, indem es eine einzelne Bildraten-Berichts-API bereitstellt und geeignete Mechanismen intern delegiert (FrameMetrics auf API 24+ usw.). Sie müssen sich keine Gedanken darüber machen, woher diese Informationen stammen, Sie können JankStats einfach fragen, wie lange es gedauert hat, und Sie erhalten Rückrufe mit diesen Informationen.
Das Erstellen und Anhören von JankStats-Daten ist im Grunde so einfach: Sie erstellen sie, und dann lehnen Sie sich zurück (okay, Ihr Code entspannt sich) und hören zu. Hier sind Beispiele für diese Schritte aus dem JankStats-Beispiel, JankLoggingActivity:
val jankFrameListener = JankStats.OnFrameListener { frameData -> // real app would do something more interesting than log this... Log.v("JankStatsSample", frameData.toString()) }jankStats = JankStats.createAndTrack( window, Dispatchers.Default.asExecutor(), jankFrameListener, )
Im Gegensatz zu neueren Benchmarking-Bibliotheken wurde JankStats erstellt, um Ergebnisse von Benutzergeräten bereitzustellen. Es ist großartig, Fehler auf Ihrem Entwicklungscomputer zu beheben, aber es hilft nicht in Situationen, in denen Ihre Anwendung von echten Menschen in der realen Welt auf sehr unterschiedlichen Geräten und unter sehr unterschiedlichen Einschränkungen verwendet wird.
JankStats bietet eine API zum Instrumentieren Ihrer Anwendung, um die benötigten Leistungsdaten bereitzustellen, und einen Berichtsmechanismus, damit Sie diese Daten hochladen und offline analysieren können.
Schließlich (hören Sie: Das ist eine wirklich neue Sache mit dieser Bibliothek) bietet JankStats eine Möglichkeit zu verstehen, was wirklich in Ihrer App vor sich ging, als Leistungsprobleme auftraten. Die Beschwerde, die wir oft gehört haben, ist, dass vorhandene Tools, Dashboards und Ansätze Ihnen nicht genug geben Kontext für Leistungsprobleme, die Ihre Benutzer möglicherweise sehen.
Beispielsweise kann Ihnen die FrameMetrics-API (eingeführt in API 24 und intern in JankStats verwendet) mitteilen, wie lange es dauert, Frames zu zeichnen, aus denen Sie Informationen über den Ruck extrahieren können. Aber es kann Ihnen nicht sagen, was damals in Ihrer Bewerbung vor sich ging. Dieses Problem müssen Sie verstehen, wenn Sie versuchen, Ihren Code zu instrumentieren und in FrameMetrics oder andere Tools zur Leistungsmessung zu integrieren. Aber jeder hat genug zu tun, ohne dass diese Art von Infrastruktur intern aufgebaut werden muss, sodass der Ruck in der Regel ungemessen bleibt und die Performance-Probleme weiterhin bestehen.
In ähnlicher Weise kann Ihnen das Android Vitals-Dashboard mitteilen, dass Ihre App Leistungsprobleme hat, aber es kann Ihnen nicht sagen, was Ihre App tat, als diese Probleme auftraten. Es ist also schwer zu wissen, was man mit diesen Informationen anfangen soll.
JankStats präsentiert PerformanceMetricsState API, ein einfacher Satz von Methoden, mit denen Sie dem System jederzeit paarweise mitteilen können, was in Ihrer Anwendung passiert StringS. Beispielsweise möchten Sie möglicherweise aufzeichnen, wenn dies angegeben ist Activity oder Fragment aktiv sind, oder wenn a RecyclerView blättert.
Hier ist beispielsweise der Code aus dem JankStats-Beispiel, der zeigt, wie RecyclerView angewiesen wird, JankStats diese Informationen bereitzustellen:
Dieser Status kann von überall in Ihre Anwendung eingefügt werden (oder sogar aus einer anderen Bibliothek), und JankStats nimmt ihn auf, wenn Ergebnisse gemeldet werden. Auf diese Weise erfahren Sie, wenn Sie Berichte von JankStats erhalten, nicht nur, wie lange die Dinge in jedem Frame gedauert haben, sondern auch, was der Benutzer während dieses Frames getan hat, was ein beitragender Faktor sein könnte.
Hier sind einige Ressourcen, um mehr über JankStats zu erfahren:
Dokumente: Unsere Website für Entwickler hat eine neue Entwicklerleitfaden die beschreibt, wie man JankStats benutzt.
Codebeispiel: Dies Projekt enthält Beispiele, die zeigen, wie JankStats-Objekte instanziiert und überwacht werden, zusammen mit der Instrumentierung Ihrer Anwendung mit wichtigen UI-Statusinformationen:
Fehler, Fehler, Fehler: Wenn Sie irgendwelche Probleme mit der Bibliothek haben oder API-Anforderungen haben, bitte einen Fehler melden.
JankStats hat gerade seine erste Alpha-Version veröffentlicht, was bedeutet: „Wir denken, dass dies eine API und Funktionalität ist, die für 1.0 sinnvoll sind, aber bitte versuchen Sie es und lassen Sie es uns wissen.“
Es gibt andere Dinge, die wir in Zukunft gerne mit JankStats machen würden, darunter das Hinzufügen einer Art Aggregationsmechanismus oder sogar die Synchronisierung mit bestehenden Upload-Diensten. Aber wir wollten diese erste Version mit grundlegenden Installationen veröffentlichen, um zu sehen, wie Sie sie verwenden und was Sie sonst noch sehen möchten. Wir hoffen, dass es in seinem jetzigen Grundzustand nützlich sein wird; allein die Möglichkeit, Statusinformationen der Benutzeroberfläche einfach zu instrumentieren und dann aufzuzeichnen, sollte besser sein, als … diese Fähigkeit nicht zu haben.
In den nächsten Beiträgen von uns Jetpack DataStore-ReiheWir behandeln einige zusätzliche Konzepte, um zu verstehen, wie DataStore mit anderen APIs kommuniziert, damit Ihnen alles zur Verfügung steht, was Sie verwenden können Produktionsumfeld. In diesem Beitrag konzentrieren wir uns auf Einspritzabhängigkeiten sind Griff. Wir verweisen auf Datenspeicher Einstellungen ich Proto codelabs durch diesen Beitrag für Codebeispiele.
In diesen Code-Labs haben wir mit unseren DataStore-Instanzen kommuniziert Einstellungen ich ProtoBaudelegierter einmal auf der höchsten Ebene der Kotlin-Datei. Dann würden wir dieselbe Instanz in Ihrer gesamten Anwendung als verwenden Einzelling:
Wir brauchen einen Singleton für die Erstellung mehr als eine Instanz aus dem DataStore für eine bestimmte Datei kann alle DataStore-Funktionen beschädigen. In einer Produktionsumgebung würden wir jedoch normalerweise eine DataStore-Instanz per erhalten Injektionsabhängigkeit. Schauen wir uns also an, wie der DataStore mit arbeitet Griffeine Suchtinjektionsbibliothek, um uns zu helfen Standard reduzieren manuelles Abhängigkeitsmanagement. Wenn Sie mit Hilt nicht vertraut sind, empfehlen wir Ihnen, es zuerst durchzugehen Verwenden Sie Hilt in Ihrer Android-App Codelab zum Erlernen grundlegender Konzepte wie z Components, Modules und andere.
Griff platzieren
Stellen Sie zunächst sicher, dass Sie alle erforderlichen Einrichtungsschritte hinzugefügt haben, um Hilt zu aktivieren:
Alle Anwendungen, die Hilt verwenden, müssen enthalten Application Klasse mit gekennzeichnet @HiltAndroidApp zum Ausführen der Hilt-Codegenerierung, einschließlich der Basisklasse für Ihre Anwendung, die als Abhängigkeitscontainer auf Anwendungsebene dient. In unserem Fall erstellen wir eine einfache TasksApp und füge es unserem hinzu AndroidManifest.xml:
DataStore-Einstellungen einfügen
Um ein zu erhalten Einstellungen für DataStore-Instanzen Durch die Injektion müssen wir Hilt sagen, wie man es richtig herstellt. Wir gebrauchen PreferenceDataStoreFactory und füge es hinzu ua Handlaufmodul:
Wir haben diese Parameter bereits in der Serie erwähnt, aber fassen wir schnell zusammen:
corruptionHandler (optional) – aufgerufen, wenn a CorruptionException wird vom Serialisierer ausgeworfen, wenn Daten nicht deserialisiert werden können, und gibt dem DataStore Anweisungen zum Ersetzen beschädigter Daten
migrations (optional) – Liste DataMigration vorherige Daten in den DataStore zu verschieben
scope (optional) – das Ausmaß, in dem IO-Operationen und Transformationsfunktionen durchgeführt werden; in diesem Fall verwenden wir wieder gleichen Bereich wie die standardmäßige DataStore-API
produceFile – erzeugt File Objekt für Preferences DataStore basierend auf geliefert Context ich namedarin gespeichert this.applicationContext.filesDir + datastore/ Unterverzeichnisse
Jetzt, da wir ein Modul haben, das Hilt anweist, wie wir unseren DataStore erstellen, müssen wir noch ein paar Anpassungen vornehmen, damit wir erfolgreich bauen können.
Hilt kann Abhängigkeiten zu anderen Android-Klassen bereitstellen, die sie haben @AndroidEntryPoint Hinweis, zusammen mit @HiltAndroidApp Pro Application ich @HiltViewModel Pro ViewModel Klassen. Wenn Sie die Android-Klasse mit markieren @AndroidEntryPoint, dann müssen Sie auch andere Android-Klassen markieren, die davon abhängen. Wenn Sie zum Beispiel a notieren Fragmentdann müssen Sie auch alle Aktivitäten markieren, bei denen Sie es verwenden Fragment.
Das bedeutet, dass wir Folgendes hinzufügen müssen:
Wir haben keine anderen in dieser Probe komplexe Injektionen, wie benutzerdefinierte Builder, Factorys oder Schnittstellenimplementierungen. Wir können uns also auf Hilt und die Konstruktorinjektion für alle anderen Abhängigkeiten verlassen, die wir durchlaufen müssen. Wir werden verwenden @Inject ein Hinweis im Klassenkonstruktor, um Hilt anzuweisen, wie seine Instanzen bereitzustellen sind:
Lassen Sie uns es schließlich vollständig loswerden preferencesDataStore ein Delegierter von der Spitze von uns TasksActivity da wir es nicht mehr brauchen. Wir werden auch die Art und Weise ändern, wie es uns gehört viewModel ist vorgesehen TaskActivityonCreatedenn seine Abhängigkeiten werden nun eingefügt:
Proto DataStore einfügen
Proto-DataStore würde einem sehr ähnlichen Muster folgen – Sie sollten zusätzlich sicherstellen, dass a UserPreferencesSerializer und genaue Anweisungen zur Migration von SharedPreferencesauf die wir näher eingegangen sind Proto DataStore-Beitrag:
Das ist es! Sie können die App jetzt ausführen und überprüfen, ob alle Abhängigkeiten jetzt korrekt eingefügt wurden.
Wir haben die Schritte weiter abgedeckt wie man DataStore mit Hilt injiziert für ein besseres Suchtmanagement, Hilta-Setup, verwenden PreferenceDataStoreFactory in unserer DataStoreModule um Hilt anzuweisen, wie unsere DataStore-Instanz ordnungsgemäß gesichert wird, und um sie schließlich den Klassen zur Verfügung zu stellen, die dies benötigen.
Begleiten Sie uns für den nächsten Beitrag aus unserer Serie, in dem wir untersuchen, wie man es verwendet Data Warehouse mit Kotlin-Serialisierung.
Erstellen Sie mit “Erinnern” eine erweiterbare Statusansicht.
Bild von Ziv Kesten
In diesem Teil unserer Serie auf Einführung von Jetpack Compose in das bestehende ProjektWir werden ein erweiterbares Listenelement erstellen, das wir in unserer Forderungsliste verwenden werden, eine Funktion, die wir mithilfe der Jetpack Compose-Benutzeroberfläche in unserer Anwendung unter erstellen Limonade. Schauen wir uns zuerst noch einmal den Bildschirm an, den wir bauen.
Wir haben bereits die folgenden Schaltflächen erstellt: “Nichts des oben Genannten” ich “NÄCHSTE”Rosa Limonade-Taste.
Heute erfahren Sie, wie Sie ein erweiterbares Listenelement erstellen, das eine Gruppe von Anforderungen an die Versicherungspolice für Haustiere darstellt.
Betrachten wir zunächst einen Einzelfall des Objekts, das wir bauen.
Zusehen, wie unser Fall abstürzt Kondition Wir können drei Komponenten identifizieren:
Text, der den Titel des Artikels enthält.
Text, der den Untertitel des Artikels enthält.
Rechtspfeil-Symbol (das animiert wird, sich vertikal zu drehen, wenn wir ein Element erweitern).
Als erstes fangen wir wie immer an zu komponieren:
Wie wir schon oft gesehen haben, schreiben wir beim Schreiben einer deklarativen Benutzeroberfläche zunächst so wenig wie möglich, nur um das Ergebnis zu beschreiben oder was wir auf dem Bildschirm sehen möchten.
Um unser erweiterbares Element zu beschreiben, schreiben wir also zuerst a Card die enthalten aRow und drinnen richten wir einTitleAndSubtitle ich Icon.
Card ein vom System geliefertes Verbundbauteil ist, kann dies einige Zeit in Anspruch nehmenelevation ich shape als Parameter, und wir können es mit a versorgenmodifier für alles andere, was wir brauchen. Der Card ist ein Container für unser erweiterbares Listenelement, damit wir es versenden elevation und einigemodifiers :
fillMaxWidth() – wird unsere Karte genauso über die gesamte Breite des Bildschirms strecken android:layout_width=”match_parent” Bi.
padding() – Es gibt uns Platz von den Rändern.
clip(RoundedCornerShape(*.dp)) – wird die Karte der gelieferten beifügen RoundedCornerShape .
clickable() – ergibt ein Lambda, das wir später zur Abwechslung verwenden können Zustand zusammengesetzt
Card( elevation = 4.dp, modifier = Modifier .fillMaxWidth() .padding(start = 15.dp, top = 15.dp, end = 15.dp) .clip(RoundedCornerShape(8.dp)) .clickable { // We will deal with the click event later } )
Bei uns Card wir haben Row (Horizontales Äquivalent LineraLayout), die Titel und ein Symbol enthält.
Der Row wird ein nehmen horizontalArrangment Parameter für den Abstand zwischen dem Symbol und dem Titel.
U Row legen wir fest TitleAndSubtitle ich Icon die horizontal ausgerichtet werden.
Row(...) { TitleAndSubtitle( title = "Expandable item title", subtitle = "There are more items below! 👇" ) Icon(...) }
Der TitleAndSubtitle ist eine Zusammensetzung, die wir geschrieben haben, um a zu haben Column (Vertikales Äquivalent LineraLayout) mit zwei Text zusammensetzbar
Der Icon ist ein zusammenbaubares System, wir geben es ihm imageVector die wir als Teil der kompositorischen Abhängigkeit erhalten, an align Modifikator und etwas Neues, das wir noch nicht gesehen haben … a graphicsLayer.
GraphicsLayer ist ein Modifikator, der zum Anwenden von Effekten auf Inhalte verwendet wird, z. B. Skalierung, Drehung, Deckkraft, Schatten und Beschneidung. In unserem Fall möchten wir das Pfeilsymbol so drehen, dass sich der Pfeil nach oben dreht, wenn das Element erweitert wird.
Innen graphicsLayer wir können benutzen animateFloatAsState die wir abgedeckt haben letzter Artikel über den pinken Limonadenknopf. Wir werden zuweisen rotationZ Eigentum hier, um eine Drehung zu erreichen 0 zu 180 Grad.
Die Rotation wird anhand eines logischen Namens entschieden erweitertDies werden unsere Komponenten sein Kondition.
In Jetpack Compose zeigt das deklarative UI-Framework wieder nur Elemente, die ihre eigenen hatten Kondition geändert, wenn wir darüber sprechen Kondition Im Zusammenhang mit der Compose-Benutzeroberfläche beziehen wir uns normalerweise speziell auf einige Funktionsvariablen, die enthalten oder darstellen Kondition.
Dies kann ein Primitiv oder ein Objekt sein. und zur Aufrechterhaltung unserer Montagefunktion Konditiones sollte während der Neuzusammenstellung nicht vergessen werden, sonst wird der Zustand bei jeder Zusammensetzung zurückgesetzt.
Unser Artikel ist erweiterbar, daher muss er einen Status haben, der angibt, ob er erweiterbar ist oder nicht erweitert.
Dazu kehren wir zu unserer anfänglichen Definition der Kompilierung zurück und fügen a hinzu Kondition Variable
Wir nehmen die Initialen Kondition das Objekt, das ist falsch (extended = false) und als Standard übergeben mutableStateOf:
var expanded by remember { mutableStateOf(false) }
mutableStateOf ist eine reaktive Strömung, ähnlich LiveDate oder StateFlow und wird boolesche Werte ausgeben, wenn wir uns ändern erweitert Variable.
merken
Wir wickeln mutableStateOf tok ua remember blockieren, damit es bei allen Neuzusammenstellungen nicht vergessen wird, sonst wird das Kondition wird die Voreinstellung sein falsch jedes Mal ExpandableListItem namens.
Wir ändern den Zustand, wenn wir auf klicken Card verwenden clickable Modifikator: Card(modifier = Modifier.clickable { expanded = !expanded})
Lassen Sie uns nun den erweiterbaren Teil der Komponente implementieren.
Jetzt müssen wir am Ende unserer Komponente einen weiteren Abschnitt hinzufügen,
Lassen Sie uns einpacken Row Element u Column damit wir ein zusätzliches Element darunter platzieren können.
@Composable ExpandableListItem() { var expanded Card(...) { /// Wrap the row in a Column Column { Row(...) { TitleAndSubtitle(...) Icon(...) }
// And add the extra items sections Column { ExtraItem(item = Item()) ExtraItem(item = Item()) } } } }data class Item ( val title: String, val date: String )
Wo ExtraItemist nur ein Row mit zwei Text zusammensetzbar.
Der AnimatedVisibility ermöglicht uns Änderungen in der Sichtbarkeitsanimation in Layouts wie z Column oder LazyColumnund gemäß dem deklarativen UI-Paradigma müssen wir keine benutzerdefinierten Animationen definieren, um dieses Verhalten zu erhalten. Wir können es jedoch leicht anpassen, wenn wir es verwenden möchten AnimationSpec.
Der AnimationSpecspeichert die Animationsspezifikation, wir können sie verwenden, um sie zu definieren Genuss, Dauer, Verzögerungen, und andere Spezifikationen im Zusammenhang mit der Anpassung von Animationen. Wenn wir Animationen wie z erweitern ich reduzieren Animationen für unsere Benutzeroberfläche können wir als verwenden.
Und indem wir diese Spezifikationen zu unseren hinzufügen AnimatedVisibility Wir können die gewünschte Animation für unser erweiterbares Element erhalten!
Hier ist der vollständige Code für unseren erweiterbaren Artikel!
Wir haben heute viel gelernt! Wir haben den Pfeil mit animiert graphicsLayer Modifikator, mit dem wir die Sichtbarkeit animiert haben AnimatedVisibilityund wir haben gelernt, wie man es benutzt Kondition in Jetpack Compose mit remember ich mutableStateOf.
Im nächsten Abschnitt fügen wir dem erweiterbaren Element ein benutzerdefiniertes Optionsfeld hinzu!
Vergiss nicht zu klatschen und zu abonnieren, aber nur wenn du denkst, ich habe es verdient!.
Trello Android wurde kürzlich eingestellt Gson zu Moshi für die JSON-Verarbeitung. Es war ein bisschen schwierig, also wollte ich den Prozess dokumentieren.
(Für den Kontext analysiert Trello Android hauptsächlich JSON. JSON wird selten serialisiert, daher liegt der Schwerpunkt hier hauptsächlich auf der Deserialisierung.)
Es gab drei Hauptgründe für den Wechsel von Gson nach Moshi: Sicherheit, Geschwindigkeitich schlechte Lebensentscheidungen.
Sicherheit – Gson versteht die Nullsicherheit von Kotlin nicht und platziert gerne Nullwerte in Eigenschaften ungleich Null. Auch die Standardwerte funktionieren nur gelegentlich (je nach Designeinstellung).
Geschwindigkeit – Genügend Benchmarks (1, 2, 3) haben gezeigt, dass Moshi normalerweise schneller ist als Gson. Nachdem wir uns umgedreht hatten, richteten wir uns ein einige Benchmarks um zu sehen, wie das Parsing in der realen Welt in unserer App verglichen wird, und wir haben eine 2x-3,5x-Beschleunigung gesehen:
Schlechte Lebensentscheidungen – Anstatt Gson zu verwenden, um JSON in einfache Modelle zu zerlegen, schrieben wir aufwändige, verwirrende, zerbrechliche benutzerdefinierte Deserialisierer, die zu viel Logik enthielten. Refactoring gab uns die Möglichkeit, diesen Architekturfehler zu korrigieren.
Warum wir uns für Moshi im Vergleich zu Wettbewerbern entschieden haben (z. Kotlin-Serialisierung), vertrauen wir im Allgemeinen Square-Bibliotheken, wir haben Moshi in der Vergangenheit für Projekte (sowohl bei der Arbeit als auch zu Hause) verwendet und fanden, dass es gut funktioniert. Wir haben keine eingehende Untersuchung von Alternativen durchgeführt.
Der erste Schritt bestand darin, sicherzustellen, dass wir Funktionsflags verwenden können, um zwischen der Verwendung unserer alten Gson-Implementierung und der neuen Moshi-Implementierung umzuschalten. Ich schrieb ein JsonInterop eine Klasse, die basierend auf dem Flag entweder alle JSON-Antworten mit Gson oder Moshi analysiert.
(Ich habe mich entschieden, die Verwendung von Tools wie z moshi-gson-interop weil ich testen wollte, ob das Moshi-Parsing vollständig funktioniert. Wenn Sie lieber gleichzeitig eine Mischung aus Gson und Moshi haben möchten, wäre diese Bibliothek nützlich.)
Gson bietet Ihnen die Möglichkeit, den verwendeten Standardschlüsselnamen zu überschreiben @SerializedName. Mit Moshi können Sie dasselbe tun @Json. Es ist alles gut und gut, aber es schien wirklich einfach, hier einen Fehler zu machen, wo die Assets in Gson Vs unter verschiedenen Namen analysiert werden. Moshi.
Also habe ich einige Unit-Tests geschrieben, die bestätigen würden, dass unsere generierten Moshi-Adapter das gleiche Ergebnis haben wie Gsons Parsing. Ich habe besonders getestet …
… dass Moshi für jede Klasse, die wir deserialisieren wollten, einen Adapter (nicht unbedingt den richtigen!) generieren kann. (Wenn er das nicht könnte, würde Moshi eine Ausnahme auslösen.)
… womit jedes Feld gekennzeichnet ist @SerializedName ist ebenfalls mit gekennzeichnet @Json (mit dem gleichen Schlüssel).
Zwischen diesen beiden Überprüfungen war es leicht zu finden, wenn ich den Fehler gemacht habe, unsere Klassen in späteren Schritten zu aktualisieren.
(Ich kann die Quelle hier nicht angeben, aber wir haben im Grunde verwendet Guavas ClassPath um alle unsere Klassen zu sammeln und sie dann auf Probleme zu scannen.)
Mit Gson können Sie generische JSON-Bäume analysieren JsonElement (und Freunde). Wir fanden dies in einigen Kontexten nützlich, wie z. B. beim Parsen von Socket-Updates (wo wir bis zu einer anfänglichen Verarbeitung nicht genau wissen würden, wie das Antwortmodell zu parsen ist).
Offensichtlich wird Moshi mit der Verwendung von Gsons Uhren nicht zufrieden sein, also sind wir dazu übergegangen, sie zu verwenden Map<String, Any?> (und manchmal List<Map<String, Any?>>) für generische Datenbäume. Sowohl Gson als auch Moshi können dies aufschlüsseln:
Darüber hinaus ist Gson freundlich, die Straße zu analysieren Leser, aber Moshi nicht. Ich habe es mit gefunden BufferedSource war eine gute Alternative, da es für alten Gson-Code in Reader konvertiert werden kann.
Die einfachsten Adapter für Moshi sind die, die Sie gerade getroffen haben @JsonClass auf sie und nennen Sie es eines Tages. Leider hatten wir, wie ich bereits erwähnte, eine Menge unglücklicher angepasster Deserialisierungslogik in unserem Gson-Parser.
Es ist ziemlich einfach Schreiben Sie einen benutzerdefinierten Moshi-Adaptersondern weil es so war so viel benutzerdefinierte Logik in unseren Deserialisierern, würde das Schreiben eines einzigen Adapters das nicht brechen. Am Ende mussten wir Interspace-Modelle erstellen, um das rohe JSON zu parsen, und uns dann an die Modelle anpassen, an die wir gewöhnt waren.
Stellen Sie sich, um ein konkretes Beispiel zu geben, vor, wir hätten a data class Foo(val count: Int)aber das eigentliche JSON, das wir bekommen, hat die Form von:
{
"data": {
"count": 5
}
}
Bei Gson konnten wir nur manuell auf den Baum schauen und die Nummer abrufen data Thema, aber wir haben festgestellt, dass darin der Wahnsinn liegt. Wir würden lieber einfach mit einfachen POJOs parsen, aber wir wollen trotzdem irgendwann Foo rausschmeißen (damit wir nicht unsere gesamte Codebasis ändern müssen).
Um dieses Problem zu lösen, würden wir neue Modelle erstellen und diese in einem benutzerdefinierten Adapter wie diesem verwenden:
@JsonClass(generateAdapter = true) data class JsonFoo(val data: JsonData)
@JsonClass(generateAdapter = true) data class JsonData(val count: Int)
object FooAdapter {
@FromJson
fun fromJson(json: JsonFoo): Foo {
return Foo(count = json.data.count)
}
}
Voila! Jetzt kann der Parser immer noch Foo auswerfen, aber wir verwenden einfache POJOs, um unsere Daten zu modellieren. Es ist einfacher zu interpretieren und zu testen.
Erinnern Sie sich, wie ich sagte, dass Gson gerne Nullwerte in Nicht-Null-Modelle analysieren würde? Es stellte sich heraus, dass wir uns (leider) an allen möglichen Stellen auf dieses Verhalten verlassen haben. Insbesondere Trello-Sockets geben oft Teilmodelle zurück – während wir also normalerweise erwarten würden, dass eine Karte mit einem Namen zurückkommt, wird dies in einigen Fällen nicht der Fall sein.
Dies bedeutete, dass wir unsere Stürze in Fällen überwachen mussten, in denen Moshi (aufgrund des Nullwerts) explodieren würde, wenn Gson wie eine Hülle glücklich wäre. Hier glänzen die Funktionsflags wirklich, da Sie den fehlerhaften Parser nicht ahnungslosen Produktionsbenutzern aufdrängen wollen!
Nachdem ich ein Dutzend dieser Fehler behoben habe, habe ich das Gefühl, dass ich viel Wertschätzung für Nicht-JSON-Technologien mit gut definierten Schemas wie Protokollpuffer. Es gibt viele Fehler, auf die ich gestoßen bin, die einfach nicht passiert wären, wenn wir einen Vertrag zwischen dem Server und dem Client gehabt hätten.
2021 war in gewisser Hinsicht das Jahr des Banners für Mobile Dev Memo: Seine Lesbarkeit, gemessen an Seitenaufrufen auf der Website und Abonnenten des Newsletters, stieg dramatisch an. Dies geschah in erster Linie, weil Apples Privacy Tracking Policy (ATT) eine Welle der Panik und Besorgnis im gesamten mobilen Ökosystem auslöste. Aber ATT hat das monopolisiert, was ich mein „Aufmerksamkeitsbudget“ nenne: eine Reihe von Themen, über die ich tief genug nachdenken kann, um mich wohl zu sezieren, da MDM nicht meine Vollzeitbeschäftigung ist und ich ihm nur begrenzt Zeit widmen kann. Infolgedessen habe ich mich in den Details der ATT-Implementierung, der Reaktion verschiedener Werbeplattformen auf ATT und einer Reihe von Beweggründen verzettelt, die erklären, warum ATT überhaupt eingeführt wurde.
Ich habe MDM vor vielen Jahren als Mittel zur persönlichen Weiterbildung gestartet. Meine These lautete: Wenn mein konzeptionelles Verständnis eines Themas stark genug ist, um daraus einen erklärenden Blogbeitrag zu machen, dann gewinne ich nicht nur Wissen durch eine disziplinierte Übung des regelmäßigen Bloggens, sondern werde dadurch auch zu einem erfahreneren und scharfsinnigeren Kommunikator . Der Umfang dieses Prozesses konzentrierte sich bisher ausschließlich auf das, was ich als Querschnitt der Erstellung, Verbreitung und des Konsums digitaler Inhalte und der wirtschaftlichen Prinzipien betrachte, die den Umgang der Benutzer mit diesen Inhalten bestimmen. Ich fühle mich wohl in diesem besonderen intellektuellen Raum, der grob durch die in meinem Buch behandelten Themen begrenzt ist, Freemium-Ökonomie2014 geschrieben
Im Jahr 2021 erweiterte sich dieser Bereich: zu kommerziellen und wettbewerbsorientierten Motiven, die nicht nur beobachtet werden können, sondern intuitiv sein müssen. Ich fühle mich in diesem Bereich weniger wohl, weil er hartnäckige Spekulationen erfordert, die funktional fast dem Verkauf ähneln. Ich mag es nicht, Annahmen und Theorien in ein überzeugendes rhetorisches Produkt zu packen. Mir macht es Spaß, komplexe, byzantinische Themen zu sezieren und sie verständlich und zugänglich darzustellen. Ich finde diesen Destillationsprozess Spaß. Ich möchte keine OpEd-Stücke schreiben.
Aber zum Thema ATT hatte ich das Gefühl, keine große Wahl zu haben. Die Berichterstattung an die Mainstream-Medien, insbesondere unmittelbar nach der WWDC 2020 – als der ATT eingeführt wurde – war, wenn ich wohltätig bin, falsch und nutzlos. Ich hatte während des Pandemoniums nach der Einführung von ATT ehrlich das Gefühl, dass, wenn ich nicht versuche, die Änderungen, die sich auf das mobile Ökosystem auswirken würden (und getan haben), zu klären, objektiv zu analysieren und aufzuschlüsseln, dass verschiedene Parteien wie Werbetechnologieanbieter, Apple selbst, und „Marketing-Gurus“ würden das Gespräch dominieren. Ich bin stolz auf die Arbeit, die ich geleistet habe, um ATT für ein breites Publikum von Marketingfachleuten, Führungskräften und Investoren an öffentlichen Märkten wie z dieses Stück, dieses Stückich dieses Stück.
Aber all diese Artikel wurden im Jahr 2020 geschrieben. Die Aufklärungsarbeit der breiten Öffentlichkeit über ATT konnte nicht mit bloßem Diskutieren enden was: das warum, die den ATT zugrunde liegenden kommerziellen Anreize darstellen, war ebenfalls wichtig. Ich habe diese Motivationen 2017 behandelt Der kommende Krieg zwischen Apple und Facebook. Es waren jedoch zeitgemäße – und fortlaufende – Kommentare erforderlich, um Marketingfachleuten dabei zu helfen, sich vorzustellen, welche Wege die Teilnehmer der öffentlichen ATT-Schlägerei zu gehen versuchten, und das war der redaktionelle Schwerpunkt dieser Website im Jahr 2021 Win-Win-Vorschlag für jeden Kommentator angesichts des aufgeladenen, polarisierten Diskurses, der ihn umgibt.
2022 plane ich, zu den Wurzeln von MDM zurückzukehren: trockene, unumstrittene und meist quantitative Analyse. Bis dahin stelle ich die 10 besten Artikel von MDM im Jahr 2021 vor, aufgelistet in absteigender Reihenfolge der Gesamtzahl der Seitenaufrufe.
In dem meistgelesenen Artikel, der 2021 auf Mobile Dev Memo veröffentlicht wurde, behaupte ich, dass Apple seine Datenschutzrichtlinie zur App-Tracking-Transparenz genutzt hat, um den Anteil des Marktes für mobile Werbung von Facebook zu übernehmen.
Ich erkläre, wie die sich verändernde digitale Datenschutzumgebung First-Party-Daten eine Betriebsprämie auferlegt und wie das von mir vorgestellte „Fortress of Content“-Konzept funktioniert dieses Stückermöglicht es großen Plattformen, die Wirksamkeit von Werbung aufrechtzuerhalten und gleichzeitig neue Datenschutzbeschränkungen einzuhalten.
Ich weise darauf hin, dass Apples Datenschutzrichtlinie zur App-Tracking-Transparenz eigene Werbenetzwerke verwendet und Strategien vorstellt, um unterschiedliche Behandlungen anzugehen.
Ich argumentiere, dass Apples Ansatz zur Verbesserung der Privatsphäre der Verbraucher durch die App „App Tracking Transparency“ nützlich ist und dass die Sprache, die in seiner Anmeldeabfrage verwendet wird, beschwerlich und einschüchternd ist.
Dies ist die Erzählung der Präsentation, die ich im Clubhausraum hielt. Diese wurde auch als Podcast-Episode veröffentlicht.
In diesem Artikel präsentiere ich eine quantitative Bewertung der Auswirkungen von ATT auf die Einnahmen von Facebook, die vom Worst-Case-, Baseline- und Best-Case-Szenario reicht. Diese Schätzung wurde Monate vor der Verbreitung von ATT berechnet; Die tatsächlichen Auswirkungen von ATT, die beobachtet wurden, nachdem Facebook im dritten Quartal 2021 Einnahmen gemeldet hatte, waren im Einklang mit meiner Worst-Case-Schätzung.
Ich gebe einen Überblick über den differenziellen Datenschutz, einen Datenschutzansatz, der in letzter Zeit zunehmendes Interesse geweckt hat, da verschiedene Plattform-Datenschutzrichtlinien und staatliche Vorschriften das Arbeitsumfeld für digitale Werbeplattformen verändern.
Ich lehne die Idee ab, dass „Ausgaben für mobile Werbung nicht einfach wegfallen können“, weil das Anzeigen-Targeting aufgrund von ATT und anderen Datenschutzinitiativen an Relevanz verliert.
In diesem Artikel enthülle ich die Logik hinter der Tatsache, dass so viele große Verbraucherprodukte Werbenetzwerke aufbauen (oder kaufen), um Werbung in ihr Kernangebot an Inhalten zu integrieren.
Ich stelle einen Rahmen für die nachhaltige Integration von NFT in die von Spielern geführte Spieleökonomie vor.
2021 war in gewisser Hinsicht das Jahr des Banners für Mobile Dev Memo: Seine Lesbarkeit, gemessen an Seitenaufrufen auf der Website und Abonnenten des Newsletters, stieg dramatisch an. Dies geschah in erster Linie, weil Apples Privacy Tracking Policy (ATT) eine Welle der Panik und Besorgnis im gesamten mobilen Ökosystem auslöste. Aber ATT hat das monopolisiert, was ich mein „Aufmerksamkeitsbudget“ nenne: eine Reihe von Themen, über die ich tief genug nachdenken kann, um mich wohl zu sezieren, da MDM nicht meine Vollzeitbeschäftigung ist und ich ihm nur begrenzt Zeit widmen kann. Infolgedessen habe ich mich in den Details der ATT-Implementierung, der Reaktion verschiedener Werbeplattformen auf ATT und einer Reihe von Beweggründen verzettelt, die erklären, warum ATT überhaupt eingeführt wurde.
Ich habe MDM vor vielen Jahren als Mittel zur persönlichen Weiterbildung gestartet. Meine These lautete: Wenn mein konzeptionelles Verständnis eines Themas stark genug ist, um daraus einen erklärenden Blogbeitrag zu machen, dann gewinne ich nicht nur Wissen durch eine disziplinierte Übung des regelmäßigen Bloggens, sondern werde dadurch auch zu einem erfahreneren und scharfsinnigeren Kommunikator . Der Umfang dieses Prozesses konzentrierte sich bisher ausschließlich auf das, was ich als Querschnitt der Erstellung, Verbreitung und des Konsums digitaler Inhalte und der wirtschaftlichen Prinzipien betrachte, die den Umgang der Benutzer mit diesen Inhalten bestimmen. Ich fühle mich wohl in diesem besonderen intellektuellen Raum, der grob durch die in meinem Buch behandelten Themen begrenzt ist, Freemium-Ökonomie2014 geschrieben
Im Jahr 2021 erweiterte sich dieser Bereich: zu kommerziellen und wettbewerbsorientierten Motiven, die nicht nur beobachtet werden können, sondern intuitiv sein müssen. Ich fühle mich in diesem Bereich weniger wohl, weil er hartnäckige Spekulationen erfordert, die funktional fast dem Verkauf ähneln. Ich mag es nicht, Annahmen und Theorien in ein überzeugendes rhetorisches Produkt zu packen. Mir macht es Spaß, komplexe, byzantinische Themen zu sezieren und sie verständlich und zugänglich darzustellen. Ich finde diesen Destillationsprozess Spaß. Ich möchte keine OpEd-Stücke schreiben.
Aber zum Thema ATT hatte ich das Gefühl, keine große Wahl zu haben. Die Berichterstattung an die Mainstream-Medien, insbesondere unmittelbar nach der WWDC 2020 – als der ATT eingeführt wurde – war, wenn ich wohltätig bin, falsch und nutzlos. Ich hatte während des Pandemoniums nach der Einführung von ATT ehrlich das Gefühl, dass, wenn ich nicht versuche, die Änderungen, die sich auf das mobile Ökosystem auswirken würden (und getan haben), zu klären, objektiv zu analysieren und aufzuschlüsseln, dass verschiedene Parteien wie Werbetechnologieanbieter, Apple selbst, und „Marketing-Gurus“ würden das Gespräch dominieren. Ich bin stolz auf die Arbeit, die ich geleistet habe, um ATT für ein breites Publikum von Marketingfachleuten, Führungskräften und Investoren an öffentlichen Märkten wie z dieses Stück, dieses Stückich dieses Stück.
Aber all diese Artikel wurden im Jahr 2020 geschrieben. Die Aufklärungsarbeit der breiten Öffentlichkeit über ATT konnte nicht mit bloßem Diskutieren enden was: das warum, die den ATT zugrunde liegenden kommerziellen Anreize darstellen, war ebenfalls wichtig. Ich habe diese Motivationen 2017 behandelt Der kommende Krieg zwischen Apple und Facebook. Es waren jedoch zeitgemäße – und fortlaufende – Kommentare erforderlich, um Marketingfachleuten dabei zu helfen, sich vorzustellen, welche Wege die Teilnehmer der öffentlichen ATT-Schlägerei zu gehen versuchten, und das war der redaktionelle Schwerpunkt dieser Website im Jahr 2021 Win-Win-Vorschlag für jeden Kommentator angesichts des aufgeladenen, polarisierten Diskurses, der ihn umgibt.
2022 plane ich, zu den Wurzeln von MDM zurückzukehren: trockene, unumstrittene und meist quantitative Analyse. Bis dahin stelle ich die 10 besten Artikel von MDM im Jahr 2021 vor, aufgelistet in absteigender Reihenfolge der Gesamtzahl der Seitenaufrufe.
In dem meistgelesenen Artikel, der 2021 auf Mobile Dev Memo veröffentlicht wurde, behaupte ich, dass Apple seine Datenschutzrichtlinie zur App-Tracking-Transparenz genutzt hat, um den Anteil des Marktes für mobile Werbung von Facebook zu übernehmen.
Ich erkläre, wie die sich verändernde digitale Datenschutzumgebung First-Party-Daten eine Betriebsprämie auferlegt und wie das von mir vorgestellte „Fortress of Content“-Konzept funktioniert dieses Stückermöglicht es großen Plattformen, die Wirksamkeit von Werbung aufrechtzuerhalten und gleichzeitig neue Datenschutzbeschränkungen einzuhalten.
Ich weise darauf hin, dass Apples Datenschutzrichtlinie zur App-Tracking-Transparenz eigene Werbenetzwerke verwendet und Strategien vorstellt, um unterschiedliche Behandlungen anzugehen.
Ich argumentiere, dass Apples Ansatz zur Verbesserung der Privatsphäre der Verbraucher durch die App „App Tracking Transparency“ nützlich ist und dass die Sprache, die in seiner Anmeldeabfrage verwendet wird, beschwerlich und einschüchternd ist.
Dies ist die Erzählung der Präsentation, die ich im Clubhausraum hielt. Diese wurde auch als Podcast-Episode veröffentlicht.
In diesem Artikel präsentiere ich eine quantitative Bewertung der Auswirkungen von ATT auf die Einnahmen von Facebook, die vom Worst-Case-, Baseline- und Best-Case-Szenario reicht. Diese Schätzung wurde Monate vor der Verbreitung von ATT berechnet; Die tatsächlichen Auswirkungen von ATT, die beobachtet wurden, nachdem Facebook im dritten Quartal 2021 Einnahmen gemeldet hatte, waren im Einklang mit meiner Worst-Case-Schätzung.
Ich gebe einen Überblick über den differenziellen Datenschutz, einen Datenschutzansatz, der in letzter Zeit zunehmendes Interesse geweckt hat, da verschiedene Plattform-Datenschutzrichtlinien und staatliche Vorschriften das Arbeitsumfeld für digitale Werbeplattformen verändern.
Ich lehne die Idee ab, dass „Ausgaben für mobile Werbung nicht einfach wegfallen können“, weil das Anzeigen-Targeting aufgrund von ATT und anderen Datenschutzinitiativen an Relevanz verliert.
In diesem Artikel enthülle ich die Logik hinter der Tatsache, dass so viele große Verbraucherprodukte Werbenetzwerke aufbauen (oder kaufen), um Werbung in ihr Kernangebot an Inhalten zu integrieren.
Ich stelle einen Rahmen für die nachhaltige Integration von NFT in die von Spielern geführte Spieleökonomie vor.
Meta, geboren auf Facebook, verzeichnete im nachbörslichen Handel einen Rückgang der Aktienkurse von mehr als 20 % gab gestern seine Ergebnisse für das vierte Quartal bekannt. Während ich dies schreibe, liegt der Aktienkurs des Unternehmens bei 249,05 $, verglichen mit 351,24 $ vor sechs Monaten und 268,10 $ vor einem Jahr. Die Marktkapitalisierung des Unternehmens, die Ende Juni vergangenen Jahres mehr als 1 Billion US-Dollar erreichte, liegt derzeit bei knapp 700 Milliarden US-Dollar.
Äpfel Anwendungsverfolgungstransparenz (ATT) Datenschutzrichtlinie versetzte Matt einen harten Schlag. Dass dieses Ergebnis unvermeidlich war, war seit der Ankündigung der Richtlinie im Juni 2020 offensichtlich, aber es war wahrscheinlich – oder zumindest vorhersehbar – schon lange vorher. 2017 habe ich geschrieben Der kommende Krieg zwischen Apple und Facebook, in dem ich ausführlich erklärte, warum Apple den Zugriff auf den Unique iOS Device Identifier (IDFA) widerrufen könnte, der zur Messung digitaler Werbung verwendet wird, um das beängstigende Wachstum von Meta zu stoppen. Und im Februar 2020, vier Monate bevor Apple ATT einführte, schrieb ich Apocalypse Coming Soon: Was passiert, wenn Ihre iOS-Werbe-ID veraltet ist?in dem ich eine hypothetische Kette von Ereignissen darstelle, die auf Apples Ankündigung zurückzuführen sind, dass die IDFA obsolet werden würde.
ATT oder eine ähnliche Politik wird seit Jahren vom Werbeökosystem erwartet. Dennoch ist der Schaden an den Aktienkursen sozialer Plattformen seit ATT bisher in Wellen aufgetreten, vierteljährlich, während die öffentlichen Märkte aufgrund der Realität von ATT aufgewacht sind. Im Januar 2021, vor mehr als einem Jahr, schrieb ich Facebook könnte 7 % der Einnahmen aus den Datenschutzänderungen von Apple erzielen. In dem Beitrag habe ich eine Analyse mehrerer Szenarien vorgestellt, wie ATT die Fähigkeit von Facebook beeinträchtigen kann, Anzeigen im Auftrag von Werbetreibenden gezielt zu schalten – und somit den Einnahmemechanismus des Unternehmens beeinträchtigt – mit den schlimmsten, zugrunde liegenden und besten Ergebnissen. Wie Das ist mir nach dem Ergebnisbericht von Meta für das dritte Quartal aufgefallen, selbst meine anfängliche Einschätzung des Worst-Case-Szenarios in diesem Beitrag war optimistisch. Und mit dem zusätzlichen Kontext der Ergebnisse dieses Quartals sieht das Worst-Case-Szenario aus dieser Analyse ziemlich sonnig aus.
Für das vierte Quartal übertraf Meta die Erwartungen der Analysten an Werbeeinnahmen auf 33,67 Milliarden US-Dollar (im Vergleich zu den erwarteten 33,4 Milliarden US-Dollar), verfehlte jedoch das obere Ende seiner Richtlinien für das letzte Quartal, das sich auf 34 Milliarden US-Dollar belief. Meta verfehlte die Erwartungen bezüglich des Gewinns je Aktie von 3,67 US-Dollar (im Vergleich zu Erwartungen von 3,84 US-Dollar). Aber insbesondere nahm Meta-in DAU von Q3 zu Q4 ab und seine MAU stieg nur um 2 mm.
In ihrer Forderung nach Verdiensten führte Meta ihre schwache Leistung im vierten Quartal auf eine Kombination aus ATT und einer Dysfunktion der Lieferkette zurück (ich beschreibe diese unglücklichen Umstände in Dieser Beitrag). Aber ATT als spezifische Krankheit dominierte Metas Ergebnisgespräch mit Analysten. Der gesamte Aufruf ist aufschlussreich, da eine Reihe wichtiger Auszeichnungen von Metas CFO David Wehner verliehen wurden, aber ich glaube, dass diese Antwort von Sheryl Sandberg den größten Kontext dafür bietet, wie lange ATT weiterhin Metas Werbeleistung belästigen wird:
Auf die Frage, was wir sehen müssen, um Werbeprodukte zu erneuern und den Return on Advertising Investment weiter zu steigern. Kurzfristig arbeiten wir, wie ich bereits sagte, an Metriken und führen neue ein, um Unternehmen dabei zu helfen, Kampagnen weiterhin mit Apples SK-Werbenetzwerk, API und Metas aggregierter Ereignismessung und Konversionsmodellierung zu messen. Wir haben also spezifische Produkte, die Menschen übernehmen können und die uns helfen.
Langfristig müssen wir Technologien zur Verbesserung der Privatsphäre entwickeln, um die Menge an personenbezogenen Daten, die wir lernen und verwenden, zu reduzieren. Verwenden Sie mehr aggregierte Daten, verwenden Sie anonymere Daten, während Sie uns dennoch ermöglichen, relevante Anzeigen zu zeigen, und es wird einige Zeit dauern. Aber eines möchte ich betonen: Es gibt viele Dinge, die kleine und große Unternehmen tun können, um die Vorteile der vielen Targeting- und Messinstrumente zu nutzen, die wir haben. Obwohl wir die Auswirkungen dieser Änderungen gesehen haben, haben wir auch nicht dort angefangen, wo 100 % unserer Millionen und Abermillionen von Werbetreibenden die verfügbaren Tools verwenden.
Während wir also weiterhin diejenigen ermutigen, die sich auf der Akzeptanzkurve befinden, diese Änderungen zu lernen und sich an sie anzupassen, gibt es auch Werbetreibende, die noch nicht einmal die Grundlagen bereitstellen, an denen wir weiter arbeiten und ihre Leistung verbessern können. Wir glauben immer noch, dass es noch viele Leistungsverbesserungen im System gibt.
Der Aufwand, den Sandberg in Metas Gewinnaufruf beschreibt, ist eine langfristige Sanierung des Werbegeschäfts von Meta: Es wird nicht geübt, Kleiderschränke aufzurüsten und Teppiche durch Holzböden zu ersetzen, sondern abzureißen und ein neues Szenario aufzubauen. Die Werbeinfrastruktur von Meta muss aufgrund von ATT und anderen unvermeidlichen Datenschutzinitiativen vollständig ersetzt werden. Das Unternehmen deutete diese Bemühungen zum Wiederaufbau an die Öffentlichkeit Vorschläge, und sie sind beeindruckend und teilweise sehr elegant. Aber das sind langfristige Projekte.
Unterdessen fordert die ATT-Reibung ihren Tribut. Und nicht nur auf Mattie; Snap-Aktien fielen wenige Stunden nach Metas Gewinnbekanntgabe um 17 %. Unter Verwendung historischer Wachstumsraten als Basislinie, wenn auch nicht perfekt, Meta verlor in der zweiten Jahreshälfte 2021 mehr als 10 Milliarden US-Dollar an Werbeeinnahmen als Folge von ATT. Das folgende Modell ist das gleiche, das verwendet wird dieser Beitragaktualisierte Daten für das vierte Quartal 2021.
Etwas, das Klarheit verdient: ATT ist eine Manifestation eines breiteren Datenschutztrends, der letztendlich die offene Übertragung von Daten zwischen Kontexten von Erst- und Drittanbietern stören wird. Ich bin ein Verfechter dieser Störung, wie ich ausgeführt habe IDFA ist der Kohlenwasserstoff des mobilen Werbeökosystems. Aber ATT ist keineswegs die einzige Initiative dafür, und tatsächlich geht die Landschaft des Datenschutzes in der Verbrauchertechnologie seit vielen Jahren in diese Richtung.