5

Ho un frammento che ha un listview.ContentProvider chiama atomico? Risparmia onPause, carica in OnActivityCreated, dati vecchi

In onPause() Sto salvando la posizione di scorrimento Y della listview in ContentProvider.

Lo stesso frammento su onResume o onActivityCreated utilizza un caricatore per afferrare la posizione di scorrimento y dal contentprovider e ripristinare la posizione di scorrimento.

Se esco dall'attività/frammento e ci ritorno, funziona, la listview ritorna all'ultima posizione aperta da quando è stata salvata sul contentprovider in onPause. Quindi il codice è corretto al 100%.

Cosa non va bene, sono i dati su una rotazione. onPause salva bene, ma il carico dopo onCreateActivity risulta nel recuperare i vecchi dati, i dati prima del salvataggio in onPause. Ne consegue che il listview ritorna alla posizione OLD quando apriva per la prima volta l'app e non la posizione in cui il listview era precedente alla rotazione.

Sembra una condizione di gara evidente che il salvataggio nel provider di contenuti durante onPause non è completato in onPause, con conseguente caricamento di vecchi dati dopo la rotazione.

Quindi una rotazione sul mio telefono si presenta come questo

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??? 

Così l'ordine guarda bene (non sembra una condizione di competizione in termini di attività/flusso frammento), ma i vecchi valori chiaramente, è caricato invece dei valori appena salvati di 59: -74.

Non mi occupo di un lavoro, so come usare saveInstanceState ecc. Ma perché dovrei raddoppiare il mio codice, c'è un modo per forzare il contentprovider a comportarsi atomicamente (cosa che pensavo che fosse già?)

Modifica: aggiunta di codice e perfezionata la domanda un po 'meglio perché non sono ancora soddisfatto che siamo più vicini a capire se contentprovider chiama il blocco mentre viene eseguito e/o se quelle chiamate sono atomiche o se è solo un fraintendimento di contentproviders e caricatori.

In onPause, mi risparmio fuori la posizione Y della scheda di prodotto

@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); 
} 

mio capire è che la chiamata di aggiornamento deve essere una chiamata di blocco, e si verifica prima che il frammento viene distrutta e prima il nuovo frammento è stato creato per gestire la rotazione

in sul curriculum I fuoco il mio caricatore

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

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

E nel mio caricatore ottengo il cursore, che ha in modo affidabile i vecchi dati dopo una rotazione, ma va bene in qualsiasi altra circostanza

@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); 
    } 
} 

Così ribadire, dopo una rotazione, il caricatore fornirà in modo coerente vecchi dati.

Sto pensando che forse il caricatore è obsoleto e non il content provider stesso? Che il cursore viene salvato e ripristinato dopo la rotazione anche se è stantio?

+0

È certamente il caso con l'app di esempio SDK 8 NotePad su Android 2.3. Imposta un punto di interruzione in onResume() (alla riga o prima della riga "mText.setTextKeepState (nota);"), apporta le modifiche a una nota, attiva la schermata, sblocca lo schermo e il testo della nota continua a fare le modifiche quando lo screenlock è stato attivato. Passa su onResume() e dopo aver eseguito "String note = mCursor.getString (COLUMN_INDEX_NOTE);" dovresti trovare il testo della nota originale ripristinato. – Huperniketes

risposta

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. 

Assumendo sopra affermazione è corretta:

solito fornitore di contenuti è veloce e non è supponiamo di prendere questo molto tempo. Ma, quando ContetnProvider è supportato da SQLite, è comprensibile che ci vorrà del tempo per inserire i dati nel database. Dove il tempo di ritardo dipenderà dalla quantità di dati e dall'hardware del dispositivo.

Ma, il problema con questo approccio è quando, l'utente ruota semplicemente lo schermo e in realtà non gli piace aspettare, per vedere i dati vengono caricati uno per uno. Rotation should be fast very fast.

alternativa su questa strada è,

  • la vostra attesa per il vostro per completare l'attività (questo bloccherà l'interfaccia utente sta creando la prossima volta e molto, molto cattiva idea)
  • si imposta tag manifesta che prenditi cura della rotazione

Ulteriore alternativa su questo percorso è creare una cache in memoria solo per la gestione del caso di rotazione. Ciò significa che ogni volta che cerchi i dati prima di provare a trovarli all'interno della cache, in caso contrario prova a caricare da ContentProvider. Puoi utilizzare lo stesso URI contenuto per la chiave della cache. E, per scrivere, scrivi prima sulla cache poi nel provider.

ContentProvider fornire alcuni grandi vantaggi, senza dubbio. Se hai bisogno di ContentProvider dovresti usarlo. Ma per gestire la rotazione puoi pensare ad altre alternative. E, la soluzione per la soluzione sarebbe, scaricando le cose su un file e rileggendole. SharedPreferences o un file tipico IO in questo momento in cima alla mia testa. Immagino che la loro sia una buona ragione per cui esistono.

Infine, solo per curiosità, hai provato caricando i dati dello stato onResume del frammento? E, si spera, setRetainInstance(boolean) non è impostato, da qualche parte nel codice.

Modifica,

per quanto ne so, non ContentProvider fornitore di alcun atomicità o filo di sicurezza. Da doc Android,

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. 

Si prega di leggere this e this

Probabilmente sarò in grado di darvi una risposta migliore se posso vedere il tuo codice.

+0

Beh, mi sto ancora chiedendo se il content provider sia o meno atomico. Quello che non capisco è che le chiamate a contentprovider stanno bloccando le chiamate afaik. E onresume e oncreate (dove carico) viene chiamato dopo onpause (dove leggo). Sarebbe una lunga strada per capire anche cosa sta effettivamente rompendo l'atomismo. Ho un lavoro da fare, ed è quello di utilizzare saveoninstancestate i dati che ho bisogno di preservare attraverso la rotazione.Si è appena reso un po 'più complicato in quanto il caricatore ritorna più volte nella nuova attività. Perché richiama più volte, anche io non lo so. –

+0

Siamo spiacenti, minhaz, ma ti manca l'essenza del problema. Comportamento che funziona su un'invocazione di onPause(), quando l'istanza Activity (o ActivityFragment) viene distrutta perché l'utente preme il pulsante Indietro, non funziona quando l'Activity (o ActivityFragment) viene distrutta perché lo schermo è bloccato dal sistema. Il comportamento di ContentProvider è diverso. Stiamo cercando il motivo per cui e come farlo fare ciò che ci si aspetta. – Huperniketes

+0

ContentProvider esegue il marshalling e lo smantellamento delle query inviate a una singola istanza di provider di contenuti da una potenziale fonte di molti. Ma questo non va oltre la comprensione del fatto che l'accesso sia o meno atomico. Aggiungerò il mio codice onPause, sto facendo il salvataggio sul thread dell'interfaccia utente, quindi la mia comprensione è che dovrebbe bloccare e la nuova attività dovrebbe quindi avere i nuovi dati quando viene creata successivamente. –

Problemi correlati