2015-07-20 4 views
5

Bei meinen eigenen Tests stieß ich nicht auf dieses Problem, aber sobald meine App veröffentlicht wurde, fingen die ANRs an zu fluten. Meine App hat derzeit 22 ANRs, wobei einige 100 mal gemeldet werden. Alle Ablaufverfolgungen scheinen von dem Versuch zu stammen, eine neue Realm-Instanz im UI-Thread zu erstellen.Realm verursacht viele ANR

"main" prio=5 tid=1 MONITOR 
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8 
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684 
| state=S schedstat=(2816413167 710323137 3658) utm=215 stm=66 core=1 
at io.realm.Realm.createAndValidate(Realm.java:~495) 
- waiting to lock <0x41df9c98> held by tid=12   (IntentService[UASyncService]) 
at io.realm.Realm.create(Realm.java:486) 
at io.realm.Realm.getInstance(Realm.java:404) 
at io.realm.Realm.getInstance(Realm.java:366) 
at io.realm.Realm.getInstance(Realm.java:347) 

Ich glaube, die Wurzel des Problems ist, wie beeender erwähnt, dass ich eine offene Realm Transaktion in einem Arbeitsthread, die meine Versuche blockieren eine Realm-Instanz auf dem UI-Thread zu erhalten verursacht ANRs.

Ich werde später wieder aktualisieren, nachdem ich eine Lösung habe.

* Bearbeiten: Hinzugefügt aktualisierte Informationen.

+1

Es scheint, Sie haben eine Schreib-Transaktion, die nicht geschlossen ist. Dies könnte den Realm blockieren, um eine neue Instanz zu öffnen. Überprüfen Sie diese PR https://github.com/realm/realm-java/pull/1297. Wenn dies der Fall ist, schlage ich vor, dass Sie Ihre Transaktion ordnungsgemäß schließen, anstatt auf die Korrektur zu warten, da die Schreibtransaktion sowieso geschlossen werden muss. – beeender

+0

@beeendeder Wenn ich also eine Transaktion in einem Worker-Thread beginne und versuche, eine neue Realm-Instanz im Benutzeroberflächenthread zu öffnen, bevor die Worker-Thread-Transaktion festgeschrieben wird, wird der UI-Thread blockiert und wartet auf die Transaktion. – MichaelAnDev

+1

Gerade jetzt, ja. Obwohl ich nicht denke, dass es das richtige Verhalten ist, könnte es einige Gründe für das aktuelle Verhalten geben, die mir nicht bekannt sind. Wenn nun eine Realm-Instanz in einem Thread erstellt wird und noch keine Instanz im Thread geöffnet ist, wird createAndValidate aufgerufen und möglicherweise durch eine Transaktion in anderen Threads blockiert. Wenn bereits eine geöffnete Instanz im Thread vorhanden ist, wird eine Referenz ohne Erstellung zurückgegeben. – beeender

Antwort

3

Realm hat dieses Problem nicht mehr.

meine Lösung zu dem Zeitpunkt als Referenz war:

Dank mir beeender in die richtige Richtung für den Hinweis und die Verknüpfung dieser PR https://github.com/realm/realm-java/pull/1297

Ausgabe

Wenn es eine anhängige Realm Transaktion Jeder Aufruf von Realm.getInstance in einem anderen Thread wird blockiert, bis die ausstehende Transaktion festgeschrieben oder abgebrochen wurde.

In meinem Fall habe ich einen IntentService, der mein Realm mit vorhandenen Benutzerdaten füllt, während ich versuche, alle aktuellen Daten anzuzeigen, indem ich Realm auf dem UI-Thread abfrage. Obwohl die Abfragen einfach sind und normalerweise keine Probleme verursachen, wird der Aufruf von Realm.getInstance blockiert, wenn eine ausstehende Transaktion im IntentService vorhanden ist. Dadurch wird der UI-Thread blockiert und möglicherweise ein ANR verursacht.

Mein erster Versuch einer Lösung war, den PR-Zweig von Beeender zu ziehen und ein Glas zu erstellen. Ich glaube, dieser Fix brachte mich einen Schritt weiter und erlaubte die Erstellung der Realm-Instanz ohne Blockierung, aber der UI-Thread wurde immer noch von kleinen Transaktionen blockiert, die ich auf dem UI-Thread ausführen wollte.

Lösung

Die Lösung I umfasst mehrere Schritte umgesetzt:

  • erstellen doppelte Objekte für alle meine Modelle. Die Duplikate erweitern RealmObject nicht, da RealmObjects nicht über Threads hinweg verwendet werden kann.
  • Alle Zugriffe auf Realm auf Hintergrundthreads verschieben. Grundsätzlich habe ich meine Abfragen in AsyncTasks eingeschlossen und Listener hinzugefügt, die die Nicht-RealmObject-Version des Modells zurückgeben.
  • Machen Sie mehr kleine Transaktionen als weniger große Transaktionen. Wo ich zuvor auf beiden Seiten einer Schleife, die viele neue RealmObjects erzeugt hat, Transaktionen gestartet und festgeschrieben habe, beginne ich jetzt und übertrage die Transaktion pro Objekt.Der Zweck davon ist, die gesamte ununterbrochene Zeit zu reduzieren, in der sich Realm in einem offenen Transaktionszustand befindet, so dass meine Abfragen, die Daten für die UI bereitstellen, abgeschlossen werden können, ohne dass sie so lange warten müssen.

Fazit

Ich war anfangs zögerlich Realm zu verwenden, weil es nach wie vor sowie die Einschränkung in der Beta ist, dass RealmObjects nicht über Threads verwendet werden. Nach einigen Tests war ich zuversichtlich, dass ich einfache Abfragen auf dem UI-Thread ohne Problem durchführen konnte (immer noch mit einem schlechten Gefühl in meinem Bauch.)

Insgesamt ist Realm ein großartiges Projekt, das man im Auge behalten muss, aber ich habe das Gefühl ist nicht bereit für große kommerzielle Projekte. Die Verwendung von Realm für dieses Projekt hat möglicherweise im Vorfeld etwas Zeit gespart, aber es hat viele unzufriedene Kunden und ein schwierig zu diagnostizierendes Problem gekostet.

* Bearbeiten: Abklären Problem.

+0

Mit diesem PR sollte getInstance nicht mehr blockiert werden. Kann ich Ihr Problem trotzdem reproduzieren? Ist es möglich, dass du mit der PR kompiliert hast, aber ein falsches Glas benutzt hast? Soll ich ein Glas für Sie zusammenstellen und mir helfen, das zu überprüfen? Vielen Dank! Der einzige Fall, den ich mir vorstellen kann, ist, dass Sie eine Instanz in einem anderen Thread erstellt haben und unmittelbar danach eine writeTransaction gestartet wurde. Und bevor die Instanz erstellt wurde, versucht ein anderer Thread, ebenfalls eine Instanz zu erstellen und wartet bereits darauf, dass die Transaktion entsperrt wird. Überprüfe, ob ich herausfinden kann, wie ich das lösen kann. – beeender

+0

@beeender Wie ich bereits erwähnt habe, brachte mich deine Lösung weiter, weil "getInstance" nicht mehr blockiert war, aber ich hatte immer noch ein Problem. Ich habe auch eine kleine Transaktion auf dem UI-Thread ausgeführt, und diese Transaktion wurde durch die Transaktion in meinem IntentService blockiert, so dass ich die Dinge sowieso überarbeiten musste. – MichaelAnDev

+0

Würdest du bitte deine Antwort etwas aktualisieren, da es kein Problem mehr ist :) und https://github.com/realm/realm-java/pull/1297 wurde zusammengeführt, um sicherzustellen, dass dies nicht noch einmal passiert. Vielen Dank! – beeender

0

Realm's introduction example zeigt sie mit einer AsyncTask, um ihre Lese-und Schreibvorgänge zu tun.

Alle kostspieligen I/O, sei es aus dem Netzwerk, eine Datenbank oder eine große Datei sollte in der Regel aus dem Hauptthread entfernt werden, da es eine träge UI verursacht. Ohne Ihren Code zu sehen, würde ich annehmen, dass Sie, wenn Sie einen ANR erhalten, wahrscheinlich etwas zu Komplexes für den Hauptthread machen.

+0

Alle signifikanten Lese- oder Schreibvorgänge, die ich gerade mache, werden an einem Worker-Thread in einem IntentService ausgeführt. Der einzige Realm-Zugriff, den ich im Hauptthread mache, sind ziemlich einfache Abfragen. – MichaelAnDev

+0

Sie sollten versuchen, StrictMode zu aktivieren, um sicherzustellen, dass Ihre Anwendung keine Vorgänge ausführt, die sich auf die Benutzeroberfläche auswirken würden. –