2014-10-27 34 views
10

Przeglądałem wiele przykładów/samouczków korzystania z SQLite w Androidzie. Załóżmy, że masz aplikację, która używa SQLite, ContentProvider, CursorLoader, niestandardowego CursorAdapter. Teraz wszystkie główne przykłady tego, że znalazłem polegać na CursorLoader, aby pobrać dane do CursorAdapter, które z natury CursorLoader dzieje się w sposób bezpieczny sposób wątku Async - UI. Jednak wszystkie te same przykłady powodują wywoływanie/usuwanie/aktualizację wywołań za pośrednictwem ContentResolver głównego wątku (np. Od onClick, onResume,). (Example) Nie zawijają one tych wywołań w AsyncTask ani nie uruchamiają osobnego wątku ani nie używają AsyncQueryHandler. Dlaczego tak wiele dobrze napisanych blogów/przykładów popełnia tak oczywisty błąd? Czy są to proste pojedynczo wstawiane/usuwać/aktualizować połączenia tak szybkie, że są wystarczająco bezpieczne, aby uruchomić z wątku głównego/interfejsu użytkownika? Jaki jest właściwy sposób wykonywania tych szybkich połączeń?Android - SQLite ContentResolver wstawić/usunąć/zaktualizować wątek interfejsu użytkownika?

+1

Twoje ostatnie zdanie prawdopodobnie ma rację: operacja zapytania jest z pewnością znacznie bardziej złożona niż pojedyncza wstawka/aktualizacja/usuwanie – pskink

Odpowiedz

4

Też się myliłem o próbkach dzwoniących w głównym wątku. Wydaje mi się, że próbki uprościły demonstracje, unikając dodatkowych wątków i wywołań zwrotnych, ponieważ pojedyncze wywołanie insert/update/delete może szybko powrócić.

Oprócz wzorca Loader dla zapytania, Android dostarczył pomocniczą klasę AsyncQueryHandler, od poziomu API 1, dla asynchronicznych operacji CRUD z pełną obsługą zwrotów CRUD. AsyncQueryHandler działa wewnątrz z HandlerThread dla operacji asynchronicznych i dostarcza wyniki z powrotem do głównego wątku.

Sądzę, że zapytania ContentProvider powinny być uruchamiane w wątkach roboczych innych niż interfejs użytkownika, a te próbki mogą nie być najlepszymi praktykami zgodnie z oficjalnym projektem.

=== edit

Znaleziony adnotacja z oficjalnych docs ramowych zobaczyć this lub this, Linia 255:

In practice, this should be done in an asynchronous thread instead of 
on the main thread. For more discussion, see Loaders. If you are not 
just reading data but modifying it, see {@link android.content.AsyncQueryHandler}. 

=== edit 2 Link do rzeczywistej android przewodniku dev zawierającej powyżej cytat

+0

Dobrze, wspomniałem również o AsyncQueryHandler w moim pytaniu ... nadal nie jest to bardzo przekonujące, że WSZYSTKIE tutoriale i przykłady, że przyszedłem Po prostu rób to, tylko dlatego, że jest prostsze i nawet nie wspominasz, że nie jest tak, jak powinieneś to robić. Aby uzyskać właściwą odpowiedź, chciałbym otrzymać coś oficjalnego od Google (członek zespołu, dokument, samouczek) lub coś podobnego (być może link do szanowanego projektu GitHub, który robi to w ten czy inny sposób), który sprawia, że ​​te lekkie połączenia Główny wątek lub używa czegoś takiego jak AsyncQueryHandler ... –

+0

W przeciwnym razie wszystko inne jest po prostu naszą opinią na ten temat ... :) –

+0

@LeoK Masz oficjalnego doktora, który o tym wspomniał. Zobacz moje zmiany. –

2

To pytanie jest w mojej głowie od dawna. Chyba zależy to od złożoności pliku, który próbujemy wstawić, zaktualizować lub usunąć. Jeśli nasza aplikacja ma zamiar wstawić lub zaktualizować duże pliki, zawsze byłoby właściwe, aby zrobić to asynchronicznie, a jeśli pliki nie będą tak duże, można to zrobić na wątku UI.

Jednak zawsze zaleca się kontynuowanie operacji bazy danych w osobnym wątku.

+0

Dzięki za odpowiedź. To naprawdę nie wyjaśnia w pełni, dlaczego tutoriale wyjaśniające najlepsze praktyki i inne aspekty prawidłowo/bezpiecznie w przypadku wkładania/usuwania/aktualizacji nigdy nie przejmują się osobnymi wątkami. Oczywiście nie przeczytałem wszystkich dobrych tutoriali, więc kilka dobrych przykładów byłoby mile widzianych. (Zwłaszcza z Google lub innych renomowanych źródeł). –

0

Myślę, że odpowiedziałeś na własne pytanie. Wierzę, że CursorLoader rozszerza AsyncTaskLoader. Połączenia wykonane z wątku UI przetwarzają tylko wywołanie CusorLoader (które używa AsyncTask). Co robi się Wezwanie nadal nie występuje w wątku interfejsu użytkownika. Wywołanie metody/funkcji, która następnie uruchamia operacje na osobnym wątku, nadal działa z dala od wątku interfejsu użytkownika.

Jaką pracę według ciebie dzieje się w wątku UI?

Proszę pokazać dziennik debugowania, jeśli to możliwe, lub przykład, w którym wydaje się, że praca jest wykonywana w interfejsie użytkownika. To nie powinno być.

Nie próbujesz się spierać, tylko chcesz wiedzieć, jak doszedłeś do wniosku o pracy z UI?

+0

Masz rację, że ładowarka jest tak asynchroniczna. Oto, co napisałem w tym pytaniu. Jednak połączenia wstawiania/usuwania/aktualizacji są dokonywane za pośrednictwem ContentReslover, a nie CursorLoader. Wszystko, co przechodzi przez ContentReslover, odbywa się w wątku UI, jeśli wywołanie odbywa się w wątku UI. Łatwo to zweryfikować, dodając Thread.sleep (5000) na początek wstawiania wstawiania do ContentProvider. Jeśli to zrobisz, zobaczysz zamrożenie interfejsu użytkownika przez 5 sekund ... –