2015-07-20 19 views
5

Podczas moich testów nie natknąłem się na ten problem, ale po opublikowaniu mojej aplikacji ANR zaczęły się pojawiać. Moja aplikacja ma obecnie 22 błędy ANR, z których niektóre są zgłaszane jako 100 razy. Wydaje się, że wszystkie ślady pochodzą z próby utworzenia nowej instancji Realm w wątku interfejsu użytkownika.Sfera wywołująca wiele błędów 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) 

wierzę korzeniem tej kwestii jest, jak beeender wspomniano, że mam otwartą transakcję dziedziną w wątku roboczego, który blokuje moje próby, aby uzyskać instancję Realm w wątku UI powodując błędów ANR.

Będę aktualizował ponownie później, po tym, jak mam rozwiązanie.

* Edycja: Dodano zaktualizowane informacje.

+1

Wygląda na to, że masz transakcję zapisu, która nie jest zamknięta. To może zablokować Królestwo, aby otworzyć nową instancję. Sprawdź to PR https://github.com/realm/realm-java/pull/1297. Jeśli tak jest, sugeruję, abyś zamknął transakcję poprawnie, zamiast czekać na naprawę, ponieważ transakcja zapisu i tak musi zostać zamknięta. – beeender

+0

@beeender Więc jeśli rozpocznę transakcję w wątku roboczym i spróbuję otworzyć nową instancję Realm w wątku interfejsu użytkownika przed zatwierdzeniem transakcji wątku roboczego, wątek interfejsu użytkownika zostanie zablokowany w oczekiwaniu na zatwierdzenie transakcji? – MichaelAnDev

+1

Teraz, tak. Chociaż nie sądzę, że jest to właściwe zachowanie, być może istnieją pewne przyczyny obecnego zachowania, którego nie jestem świadomy. Teraz, gdy utworzysz instancję Realm w jednym wątku i nie ma jeszcze otwartej instancji w wątku, zostanie wywołana funkcja createAndValidate, która może zostać zablokowana przez transakcję w innych wątkach. Ale jeśli istnieje już jedno otwarte wystąpienie w wątku, odniesienie zostanie zwrócone bez tworzenia. – beeender

Odpowiedz

3

Sfera nie ma już tego problemu.

Dla porównania moje rozwiązanie w tym czasie było:

Dzięki beeender dla wskazujące mnie we właściwym kierunku i łączenie tego PR https://github.com/realm/realm-java/pull/1297

Issue

Kiedy jest w toku transakcja Realm każde wywołanie Realm.getInstance w innym wątku zostanie zablokowane do czasu zatwierdzenia lub anulowania oczekującej transakcji.

W moim przypadku mam IntentService, która wypełnia mój obszar istniejącymi danymi użytkownika, podczas gdy ja staram się wyświetlać wszelkie aktualne dane przez zapytanie Realm w wątku UI. Chociaż zapytania są proste i nie powodują problemów w normalny sposób, jeśli w IntentService trwa transakcja oczekująca, wywołanie Realm.getInstance zostanie zablokowane, blokując wątek UI, potencjalnie powodując ANR.

Moja pierwsza próba rozwiązania polegała na przyciąganiu gałęzi PR-a i utworzeniu słoja. Wierzę, że ta poprawka doprowadziła mnie o krok dalej, umożliwiając utworzenie instancji Realm bez blokowania, ale wątek interfejsu użytkownika był nadal blokowany przez małe transakcje, które próbowałem wykonać w wątku UI.

Rozwiązanie

Rozwiązanie I wdrożone obejmuje kilka etapów:

  • Tworzenie duplikatów obiektów dla wszystkich moich modeli. Duplikaty nie rozszerzają RealmObject (ponieważ RealmObjects nie mogą być używane w wątkach).
  • Przenieś wszystkie dostępy do dziedziny na wątki w tle. Zasadniczo opakowałem moje zapytania w AsyncTasks i dodałem detektory, które zwracają wersję modelu inną niż RealmObject.
  • Wykonuj więcej małych transakcji niż mniej dużych transakcji. Gdzie wcześniej zacząłem i zatwierdziłem transakcje po obu stronach pętli, która stworzyła wiele nowych obiektów RealmObject, teraz rozpoczynam i zatwierdzam transakcję na obiekt.Ma to na celu zmniejszenie całkowitego niezakłóconego czasu, w którym Realm może znajdować się w stanie otwartej transakcji, więc moje zapytania dostarczające dane do interfejsu użytkownika mogą zostać ukończone bez konieczności czekania tak długo.

Wnioski

Początkowo byłem niezdecydowany używać Realm powodu wciąż jest w fazie beta, a także zastrzeżenie, że RealmObjects nie może być stosowany w całej wątków. Po kilku testach czułam się pewna, że ​​mogę bezbłędnie wykonywać proste zapytania w wątku UI (nadal z poczuciem winy w moim wnętrzu).

Ogólne królestwo to świetny projekt, który warto mieć na oku, ale czuję, że nie jest gotowy do dużych projektów komercyjnych. Korzystanie z Realm w tym projekcie mogło zaoszczędzić trochę czasu, ale kosztowało wielu niezadowolonych klientów i trudny do zdiagnozowania problem.

* Edycja: sklarowano problem.

+0

Przy tym PR getInstance nie powinno być już blokowane. Czy mimo to mogę odtworzyć Twój problem? Czy to możliwe, że skompilowałeś z PR, ale użyłeś niewłaściwego słoika? Czy mam skompilować dla ciebie słoik i pomóż mi go zweryfikować? Dzięki! Jedyny przypadek, jaki mogę sobie wyobrazić, to stworzenie instancji w innym wątku i zaraz po tym rozpoczęło się writeTransaction. A przed utworzeniem instancji inny wątek próbuje również utworzyć instancję i zaczekać na odblokowanie transakcji. Sprawdźmy, czy mogę wymyślić, jak rozwiązać ten problem. – beeender

+0

@beeender Jak już wspomniałem, twoja poprawka doprowadziła mnie do tego, że 'getInstance' nie była już zablokowana, ale wciąż miałem problem. Robiłem także małą transakcję w wątku UI i ta transakcja została zablokowana przez transakcję w mojej IntentService, więc i tak musiałem przerobić rzeczy. – MichaelAnDev

+0

Czy możesz zaktualizować odpowiedź, ponieważ nie jest to już problem :) i https://github.com/realm/realm-java/pull/1297 został scalony, aby upewnić się, że to się nie powtórzy. Dzięki! – beeender

0

Realm's introduction example pokazuje je za pomocą AsyncTask do wykonywania ich odczytów i zapisów.

Dowolne kosztowne operacje wejścia/wyjścia, czy to z sieci, bazy danych, czy z dużego pliku, powinny być zwykle wyłączone z głównego wątku, ponieważ spowoduje to spowolnienie interfejsu użytkownika. Nie widząc twojego kodu, domyślam się, że jeśli otrzymujesz ANR, prawdopodobnie robisz coś zbyt skomplikowanego dla głównego wątku.

+0

Wszystkie istotne odczyty lub zapisy wykonywane są w wątku roboczym w usłudze IntentService. Jedyny dostęp do obszaru, który robię w głównym wątku, to dość proste zapytania. – MichaelAnDev

+0

Należy spróbować włączyć StrictMode, aby upewnić się, że aplikacja nie wykonuje żadnych operacji, które mogłyby wpłynąć na interfejs użytkownika. –

Powiązane problemy