5

Mam fragment, który ma widok listy.ContentProvider dzwoni atomowo? Zapisz na onPause, załaduj w OnActivityCreated, stare dane

W onPause() Zapisuję pozycję przewijania Y widoku listy w dostawcy treści.

Ten sam fragment w trybie onResume lub onActivityCreated używa programu ładującego do przechwytywania pozycji przewijania y od dostawcy treści i przywracania pozycji przewijania.

Jeśli wyjdę z działania/fragmentu i powrócę do niego, to działa, widok listy powraca do ostatniej otwartej lokalizacji, ponieważ został zapisany do dostawcy treści w trybie onPause. Kod jest w 100% czysty.

Co nie jest w porządku, to dane na obrocie. onPause zapisuje dobrze, ale ładunek po onCreateActivity powoduje pobieranie starych danych, danych przed zapisaniem w onPause. Powoduje to, że widok listy powraca do pozycji OLD, kiedy po raz pierwszy otworzyli aplikację, a nie pozycji, w której widok listy był przed rotacją.

Wydaje się oczywistym warunkiem wyścigu, że zapisywanie do dostawcy treści podczas operacji onPause nie jest zakończone w operacji onPause, co powoduje, że stare dane są ładowane po obróceniu.

Więc obracania na mój telefon wygląda tak

01:31:33.026: ThreadViewerFragment.java(235):onPause Saved(position:Yposition): 59:-74 
01:31:33.256: ThreadViewerFragment.java(194):onActivityCreated 
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149 //initial load is of old values 
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149 
01:31:33.596: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 59:-74 //this is loaded due to notification by the save in onPause which is supposed to be finished before recreating the new fragment??? 

Więc kolejność wygląda dobrze (nie wyglądać wyścigu pod względem aktywności/przepływu fragment), lecz wyraźnie, to obciążonych starymi wartościami zamiast z właśnie zapisanych wartości 59: -74.

Nie jestem po pracy, wiem jak używać saveInstanceState itp. Ale dlaczego powinienem podwoić swój kod, czy istnieje sposób zmuszenia dostawcy treści do zachowania atomowego (co myślałem, że już było?)

Edycja: dodawanie kodu i ulepszanie pytania nieco lepiej, ponieważ nadal nie jestem zadowolony, że jesteśmy bliżej zrozumienia, jeśli wywołania contentprovider blokują się podczas wykonywania i/lub jeśli te połączenia są atomowe lub jeśli to tylko nieporozumienie dostawców treści i ładowarek.

W OnPause, ja ratuję się pozycję Y liście produktów

@Override 
public void onPause() { 
    super.onPause(); 

    Utils.logv("onPause Saved position: " + mLastRead + ", " + mYPos); 

    ContentValues contentValues = new ContentValues(); 
    contentValues.put(ProductsContract.Products.Y_POS, mYpos); 

    int updateCount = getActivity().getContentResolver().update(
       Uri.parse(ProductsContract.Products.CONTENT_URI + "/" + mId), 
       contentValues, null, null); 
} 

My rozumiemy to, że wezwanie do aktualizacji powinna być wezwanie blokowanie i występuje przed fragment jest zniszczona, a przed nowy fragment został stworzony, aby obsługiwać obrót

IN CV uruchomię mój ładowarka

public void onResume() { 
    super.onResume(); 

    getLoaderManager().initLoader(PRODUCTS_LOADER_ID, null, this); 
} 

I w moim ładowarki, pojawia się kursor, który ma niezawodnie stare dane po obracać, ale jest w porządku w innych okolicznościach

@Override 
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 
    if(cursor.moveToFirst()){ 
     mYpos = cursor.getInt(cursor.getColumnIndex(ProductsContract.Products.Y_POS)); 
     Utils.logv("loader: " + mYpos); 
    } 
} 

więc przekształcenie po obracać, ładowarka będzie konsekwentnie dostarczać stare dane.

Myślę, że być może to ładowacz jest nieświeży, a nie sam dostawca treści? Że kursor jest zapisywany i przywracany po obrocie, mimo że jest nieaktualny?

+0

Z pewnością jest tak w przypadku przykładowej aplikacji SDK 8 NotePad w systemie Android 2.3. Ustaw punkt przerwania w onResume() (w linii lub przed wierszem "mText.setTextKeepState (note);"), wprowadź zmiany do notatki, aktywuj blokadę ekranu, odblokuj ekran, a tekst notatki będzie nadal zawierał zmiany wprowadzone podczas blokady ekranu został aktywowany. Przejdź przez onResume() i po wykonaniu "String note = mCursor.getString (COLUMN_INDEX_NOTE);" powinieneś znaleźć oryginalny tekst notatki przywrócony. – Huperniketes

Odpowiedz

1
It seems like an obvious race condition that the save to the content provider is not completed in the onPause before it is loaded after the rotate. 

Przyjmując powyższe stwierdzenie jest poprawne:

Zazwyczaj dostawcy treści jest szybkie i nie jest przypuszczać, aby wziąć to dużo czasu. Jednak, gdy ContetnProvider jest wspierany przez SQLite, zrozumiałe jest, że wprowadzenie danych do bazy danych zajmie trochę czasu. Gdzie czas opóźnienia będzie zależeć od ilości danych i sprzętu urządzenia.

Jednak problem z tym podejściem polega na tym, że użytkownik po prostu obraca ekran i naprawdę nie lubi czekać, aby dane były ładowane jeden po drugim. Rotation should be fast very fast.

alternatywna na tej drodze jest

  • Twój czekać na do wykonania zadania (to zablokuje UI tworzony następnym razem i bardzo, bardzo zły pomysł)
  • ustawić oczywisty znak, który zadbaj o rotację.

Kolejną alternatywą na tej ścieżce jest utworzenie pamięci podręcznej w pamięci tylko do obsługi przypadku obrotu. Oznacza to, że za każdym razem, gdy najpierw poszukujesz danych, próbujesz znaleźć je w pamięci podręcznej, jeśli nie, spróbuj załadować od ContentProvider. Możesz użyć tego samego identyfikatora URI treści dla klucza pamięci podręcznej. I, pisząc, napisz najpierw w pamięci podręcznej, a następnie w dostawcy.

ContentProvider zapewniają wspaniałe korzyści, bez wątpienia. Jeśli potrzebujesz ContentProvider, powinieneś go użyć. Ale w przypadku rotacji możesz wymyślić inną alternatywę. A rozwiązaniem może być Way around, zrzucanie rzeczy do pliku i czytanie tego z powrotem. SharedPreferences lub typowy plik IO teraz na szczycie mojej głowy. Sądzę, że ich dobry powód istnieje.

Wreszcie, tylko z ciekawości, czy próbowałeś, ładując dane stanu onResume stan fragmentu? I mam nadzieję, że setRetainInstance(boolean) nie jest ustawiony gdzieś w kodzie.

Edit,

AFAIK, ContentProvider nie atomowości lub dowolnego dostawcy wątek bezpieczeństwo. Z Android doc,

the methods query(), insert(), delete(), update(), and getType()—are called 
from a pool of threads in the content provider's process, not the UI thread 
for the process. Because these methods might be called from any number of 
threads at the same time, they too must be implemented to be thread-safe. 

Proszę przeczytać this i this

Prawdopodobnie będę mógł dać lepszą odpowiedź, czy mogę zobaczyć swój kod.

+0

Cóż, wciąż się zastanawiam, czy dostawca zawartości nie jest atomowy. Nie rozumiem, że wywołania contentprovider blokują połączenia afaik. I onresume i oncreate (gdzie ładuję) jest wywoływany po onpause (gdzie czytam). Zrozumiałbym, co tak naprawdę przełamuje atomizm. Mam pracę dookoła, a to polega na użyciu saveoninstancestate danych, które muszę zachować przez rotację.Jest to nieco bardziej skomplikowane, ponieważ program ładujący powraca wielokrotnie w nowej aktywności. Dlaczego oddzwania wiele razy, ja też nie wiem. –

+0

Przepraszam, minhaz, ale brakuje ci sedna problemu. Zachowanie, które działa na jednym wezwaniem OnPause(), gdy aktywny (lub ActivityFragment) instancja jest zniszczone, ponieważ użytkownik kliknie przycisk wstecz, nie działa, gdy aktywny (lub ActivityFragment) ulega zniszczeniu, ponieważ ekran jest zablokowany przez system. Zachowanie ContentProvider jest inne. Szukamy przyczyny i sposobu, aby zrobić to, czego się oczekuje. – Huperniketes

+0

ContentProvider robi rozrządowych i unmarshalling zapytań wysyłanych do jednej instancji dostawcy treści z potencjalnym źródłem wielu. Ale to nie idzie dalej w zrozumieniu pogoda lub nie dostęp jest atomowy. dodam mój kod OnPause, robie ustawiony na wątku UI, więc mój zrozumienia jest to, że powinien on blokować i nowa działalność powinna wtedy mieć nowe dane, gdy zostanie utworzony w następstwie tego. –

Powiązane problemy