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.
Wie bei den meisten akzeptiert Antworten auf SO, werden Sie höchstwahrscheinlich verwenden ActivityManager.getRunningTasks Methode zum Bestimmen, welche Anwendung vorhanden ist Vordergrund Kondition. Für diejenigen, die es nicht wissen Vordergrund ich Hintergrund Android-Anwendungsstatus, hier ist eine kurze Beschreibung,
Für unseren Anwendungsfall Vordergrund dies würde nur bedeuten, dass die Anwendung für den Benutzer nicht sichtbar ist (evtl Dom die Taste wird gedrückt; in diesem Fall wechselt die Anwendung zu Vor kurzem Seite).
Lassen Sie mich auf den Punkt zurückkommen, Ihre erste Beobachtung in offiziellen Dokumenten ActivityManager.getRunningTasks wird sagen, dass die Methode für Android Lollipop (API-Level 21) veraltet ist. ich die der Grund, den Android vorschlägt Es ist ziemlich überzeugend,
Mögen Build.VERSION_CODES.LOLLIPOPDiese Methode steht Anwendungen von Drittanbietern nicht mehr zur Verfügung: Die Einführung neuer dokumentorientierter Methoden bedeutet, dass Anruferinformationen verloren gehen können.
Sie werden auf diese Beobachtung auch stoßen, wenn Sie sich die schrillen Kommentare unter den SO-Antworten ansehen, die die Verwendung von nahelegten ActivityManager.getRunningTasks .
Der Zugriff auf die letzten Aktivitäten von Benutzern ohne Zustimmung kann dazu führen, dass Benutzer glauben, dass Ihre Anwendung eine Art Spyware-Software ist, die auf ihrem Gerät installiert ist. Außerdem könnten Entwickler die Nutzungsmuster von Apps untersuchen, die von Ihrem Gerät gestohlen wurden, um ihre eigenen Apps zu verbessern, alles aus Ihren privaten Daten. Also die Entscheidung zur Aufhebung ActivityManager.getRunningTasks von Android war ein naheliegender Schritt für die Sicherheit der Benutzerdaten.
Wenn Sie nach einem veralteten Ersatz suchen ActivityManager.getRunningTasks Sie werden wahrscheinlich eine Lösung finden, indem Sie verwenden ActivityManager.getRunningAppProcesses Methode. Aber aus irgendeinem Grund gibt die Methode nur den Paketnamen des aktuellen Prozesses zurück, also der Anwendung, die diese Methode aufgerufen hat. Keine andere vom Benutzer verwendete Anwendung wird über die Methode zurückgegeben.
Android scheint diese Methode auch eingeschränkt zu haben, um dem Benutzer eine verbesserte Privatsphäre zu bieten. Außerdem suchen wir nach einem Weg, der mehr ist offiziell und durch Android vor zukünftiger Veralterung geschützt.
Der UsageStatsManager -Klasse bietet Zugriff auf den Gerätenutzungsverlauf und Statistiken. In Anbetracht unseres Anwendungsfalls werden wir spezifische verwenden UsageStatsManager.queryUsageStats eine Methode zum Überprüfen der letzten Benutzeraktivitäten oder kürzlich verwendeten Anwendungen, mit Zustimmung des Nutzers.
Schritt 1: 🔐 Beantragung von Genehmigungen
Offizielle Dokumentation für UsageStatsManager Länder
Die meisten Methoden auf dieser API erfordern eine Genehmigung android.permission.PACKAGE_USAGE_STATS. Das Erklären der Erlaubnis impliziert jedoch die Absicht, die API zu verwenden, und der Gerätebenutzer muss die Erlaubnis dennoch über die Einstellungs-App erteilen.
Es ist also gut, diese Berechtigung zu unserer hinzuzufügen AndroidManifest.xml ,
Clip 1: PACKAGE_USAGE_STATS-Berechtigung zu AndroidManifest.xml hinzufügen
Beachten Sie, dies ist ein Sondergenehmigung und nicht ein Erlaubnis während der Ausführung mögen CAMERA oder WRITE_EXTERNAL_STORAGE die von der Anwendung angefordert werden können. Dies ist offensichtlich, da es sich um eine sensible Erlaubnis zum Zugriff auf die persönlichen Daten des Benutzers handelt, die dem Benutzer bekannt sein muss.
Schritt 2: 🔑 Überprüfen Sie den Status der Genehmigung und suchen Sie danach
In der Logik der Anwendung müssen wir zunächst feststellen, ob dies die vom Benutzer erteilte Erlaubnis ist, und wenn nicht, müssen wir danach fragen. Leider können wir den Status dieser Berechtigung nicht überprüfen ContextCompat.checkSelfPermission weil es sich um eine Sondergenehmigung handelt. Sondergenehmigungen verwaltet er lieber AppOpsManager Dies ist die Klasse, die verwendet wird, um alle Anwendungen zu verwalten und den Zugriff zu steuern.
Clip 2: Überprüfen Sie den Berechtigungsstatus von PACKAGE_USAGE_STATS mit AppOpsManager
Fragen PACKAGE_USAGE_STATS Berechtigungen, die wir nicht verwenden können ActivityCompat.requestPermissions Methode bzw ActivityResultContracts.RequestPermission() weil dies keine Genehmigung während der Ausführung ist, wie wir zuvor besprochen haben. Stattdessen müssen wir den Benutzer zur Seite „Einstellungen“ navigieren, wo der Benutzer diese Anwendungsberechtigung erteilt,
Clip 3: Fordern Sie die Berechtigung PACKAGE_USAGE_STATS an, nachdem Sie den Lizenzstatus überprüft habenNutzungsdateneinstellungen wie auf einem Android 9-Gerät (Samsung J7) beobachtet.
Schritt 3: imanjeLaden Sie das Nutzungsereignis herunter
Sobald der Benutzer die Erlaubnis erteilt, können wir nun auf den Geräteverlauf des Benutzers zugreifen und überprüfen, welche Apps in der Vergangenheit mit Zustimmung des Benutzers verwendet wurden. Jetzt können wir verwenden UsageStatsManager.queryEvents Methode zum Abrufen von Nutzungsereignissen.
Clip 4: Nutzungsereignisse mit der Methode „usageStatsManager.queryEvents“ anfordern.
Wie im Code vermerkt, queryEvents Die Methode benötigt zwei Argumente, beginTime ich endTime . beginTime gibt den Zeitpunkt (in der Vergangenheit) an, ab dem Ereignisse heruntergeladen werden sollen, doc endTime gibt die Zeit an, bis zu der wir Ereignisse benötigen. Beachten Sie, dass beide Argumente sind Unix-Zeit Werte, was beim Gebrauch deutlich wird System.currentTimeMillis() im obigen Code-Snippet.
Der usageEvents.getNextEvent gibt Ereignisse in chronologischer Reihenfolge zurück, also müssen Sie sie sortieren.
Wenn Sie auf Android R-Geräte abzielen, sollten Sie es sich unbedingt ansehen Schritt 5.
Überprüfen Sie die Ausgabe unten, wobei jede Zeile den Paketnamen und den Zeitstempel anzeigt, in dem der Benutzer auf das Paket zugegriffen hat.
Code-Snippet-Ausgabe 4. Die letzte Zeile in der obigen Ausgabe zeigt den Namen des aufrufenden Pakets.
Schritt 4: Vom Benutzer installierte Anwendungen filtern (optional)
Wie Sie sehen können, enthält die obige Ausgabe auch einige Systemanwendungen wie com.sec.android.app.launcher Dies ist die Standardanwendung, die auf Samsung-Geräten ausgeführt wird. Dies liegt daran, dass der Benutzer zum Startbildschirm wechselt, um eine andere Anwendung zu öffnen oder die Geräteeinstellung zu ändern. Möglicherweise möchten Sie diese Systemanwendungen filtern, sodass nur von Benutzern installierte Anwendungen in der Ausgabe sichtbar sind. Wir können eine Methode erstellen, die a zurückgibt Map die vom Benutzer installierte Anwendungen mit ihren Paketnamen und Tags (Anwendungsname, sichtbar für den Benutzer) enthält. Wir können von Benutzern installierte Apps filtern und auch deren Tag abrufen (falls Sie dies in der Logik Ihrer App weiterverarbeiten möchten).
Clip 5: Holen Sie sich einen „Ordner“, der Paketnamen und Tags der vom Benutzer installierten Anwendungen enthält
Schritt 5: Stellen Sie sicher, dass der Benutzer entsperrt ist (mit Android R)
Wenn Sie die Dokumentation auf überprüft haben UsageStatsManager.queryEvent Methode, werden Sie entdecken
Hinweis: Ab Android Rwenn sich das Gerät des Benutzers nicht im entsperrten Zustand befindet (wie definiert durch UserManager#isUserUnlocked()), dann null Wird zurückerstattet.
Mit Android R können wir diese Methode also nicht ausführen, wenn das Gerät gesperrt ist. Wir müssen also sicherstellen, dass der Benutzer entsperrt ist,
Clip 6: Überprüfen Sie, ob der Benutzer mit UserManager entsperrt ist
Denken Sie auch daran UserManager.isUserUnlocked Die Methode ist für API 24 und höher verfügbar, und daher werden wir sie ua bereitstellen if Erklärung.
Dies markiert das Ende unserer Implementierung. Verbinden Sie sich mit einem physischen Gerät und die App funktioniert!
Ich hoffe, dir hat der Blog gefallen! Für Anregungen und Anfragen können Sie gerne einen Kommentar hinterlassen. Lesen Sie weiter, studieren Sie und haben Sie einen schönen Tag!