2011-12-22 24 views
29

Desidero implementare un AsyncTaskLoader nel mio progetto utilizzando il pacchetto di compatibilità, quindi ho seguito il manuale Loader in Documenti Android.AsyncTaskLoader non viene eseguito

Il problema è che il caricatore non fa nulla, a quanto pare non è mai chiamato loadInBackground()

alcuna idea di ciò che non va nel mio codice? (ExpandableListFragment estende Fragment, ma non sovrascrive alcun metodo critico)

Grazie :-)

/** EDIT:

ho capito (in ritardo, io sono un deficiente) che AsyncTaskLoader è una classe astratta quindi ho bisogno di sottoclasse esso ... m (__) m lascio la questione nel caso in cui qualcuno viene qui dietro di me, chi lo sa ...

public class AgendaListFragment extends ExpandableListFragment implements 
     LoaderManager.LoaderCallbacks<JSONArray> { 

    private TreeMap<Integer, ArrayList<Evento>> mItems = new TreeMap<Integer, ArrayList<Evento>>(); 
    private AgendaListAdapter mAdapter; 
    private ProgressBar mProgressBar; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View root = inflater.inflate(R.layout.fragment_agenda, container); 
     mProgressBar = (ProgressBar) root.findViewById(R.id.loading); 
     return root; 

    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     mAdapter = new AgendaListAdapter(getActivity()); 
     setListAdapter(mAdapter); 

     getLoaderManager().initLoader(0, null, this); 

    } 

    @Override 
    public Loader<JSONArray> onCreateLoader(int arg0, Bundle arg1) { 
     mProgressBar.setVisibility(View.VISIBLE); 
     return new AsyncTaskLoader<JSONArray>(getActivity()) { 
      @Override 
      public JSONArray loadInBackground() { 

       return getDataFromService(AgendaServices.LISTADO_MES); 

      } 

     }; 
    } 

    @Override 
    public void onLoadFinished(Loader<JSONArray> loader, JSONArray data) { 

     // Some stuff to turn JSONArray into TreeMap 

     mProgressBar.setVisibility(View.GONE); 
     mAdapter.setItems(mItems); 

    } 

    @Override 
    public void onLoaderReset(Loader<JSONArray> arg0) { 
     mAdapter.setItems(null); 
     mProgressBar.setVisibility(View.VISIBLE); 

    } 

} 
+3

Il tuo 'AsyncTaskLoader' sembra mancare un sacco di cose, come' deliverResults() '. Ho due implementazioni 'AsyncTaskLoader' nel mio progetto' LoaderEx' che potresti voler esaminare a fini di confronto: https://github.com/commonsguy/cwac-loaderex – CommonsWare

+0

Sembra che io sia un disastro e non mi sono reso conto che è una classe astratta ... Quindi ora so perché ho trovato solo alcuni esempi che la sottoclassi. Grazie! –

risposta

62

Penso che la soluzione migliore per il pacchetto di compatibilità è quello di sovrascrivere il metodo AsyncTaskLoader.onStartLoading.

ad es.

@Override 
protected void onStartLoading() { 
    if(dataIsReady) { 
    deliverResult(data); 
    } else { 
    forceLoad(); 
    } 
} 
+0

Ho fatto questo alla fine MrGreen. Grazie! –

+0

Sì grazie David!Riportalo in un post con il codice sorgente: http://blog.blundell-apps.com/tut-asynctask-loader-using-support-library/ – Blundell

+2

Anche il controllo di "takeContentChanged" sembra un passo importante. –

7

Questa è esattamente una correzione ma dovrebbe funzionare. Sono abbastanza sicuro che la libreria di compatibilità sia danneggiata. Prova questo:

getLoaderManager().initLoader(0, null, this).forceLoad(); 
+0

Questo è un altro modo per farlo :-D. –

+5

Funzionerebbe, ma probabilmente è meglio applicare il 'Loader ' correttamente (come suggerisce davidshen84, implementando il metodo 'onStartLoading()' invece di chiamare 'forceLoad()' direttamente in 'Attività' e/o 'Fragment'. –

1

Guardando discussione al https://code.google.com/p/android/issues/detail?id=14944, controllando per takeContentChanged sembra essere importante passo troppo.

protected void onStartLoading() { 
    if (mCursor != null) { 
     deliverResult(mCursor); 
    } 
    if (takeContentChanged() || mCursor == null) { 
     forceLoad(); 
    } 
} 
+0

Non ha senso usare qui "takeContentChanged" - non influirà sul risultato. Se 'mCursor' è nullo - verrà chiamato' forceLoad'. Se non lo è, verrà chiamato 'deliverResult'. –

+1

Perché dici "takeContentChanged" non ha senso? http://developer.android.com/reference/android/content/AsyncTaskLoader.html L'esempio di Google fa uso di questo. –

+0

Perché quando un'attività entra in 'onPause()' e ritorna con 'onResume()' il caricatore viene avvisato e richiama 'onStartLoading()' di nuovo. Quindi 'takeContentChanged()' (se 'onContentChanged()' è stato chiamato in precedenza) costringerà ad aggiornare 'mCursor' con le ultime modifiche disponibili. Tuttavia, sul primo 'if' vorrei mettere invece' if (mCursor! = Null &&! TakeContentChanged()) '. – AxeEffect

-2

Avevo ancora il problema che il caricamento dei dati non è stato chiamato. Ho finalmente rimosso il AsyncTaskLoader (la versione della libreria di supporto) e usato solo AsyncTask (non dalla libreria di supporto) per fare il lavoro. E ha funzionato.

Potrebbe essere sufficiente anche per le vostre esigenze.

Descrizione ed esempio: http://developer.android.com/reference/android/os/AsyncTask.html.

È necessario estendere la classe AsyncTask.

Il metodo doInBackground farà il lavoro e nel metodo OnPostExecute si otterrà il risultato. Per avviare AsyncTask, chiamerai il metodo esegui sulla sua istanza. Vedi il link.

+1

AsyncTask e AsyncTaskLoader sono cose molto diverse ... AsyncTaskLoader ha diversi vantaggi. Dovresti cercare un po 'di più –

3

Cheok Yan Cheng ha assolutamente ragione:

Controllo per takeContentChanged sembra un passo importante anche.

Se si scrive il metodo come questo:

protected void onStartLoading() { 
    forceLoad(); 
} 

si '' noterà che quando un'attività bambino si avvicina e poi si torna al genitore uno, onStartLoading (e così loadInBackground) sono chiamati ancora!

Cosa puoi fare? Impostare una variabile interna (mContentChanged) su true all'interno del costruttore; quindi controlla questa variabile all'interno di onStartLoading. Solo quando è vero, iniziare a caricare per davvero:

package example.util; 

import android.content.Context; 
import android.support.v4.content.AsyncTaskLoader; 

public abstract class ATLoader<D> extends AsyncTaskLoader<D> { 

    public ATLoader(Context context) { 
     super(context); 
     // run only once 
     onContentChanged(); 
    } 

    @Override 
    protected void onStartLoading() { 
     // That's how we start every AsyncTaskLoader... 
     // - code snippet from android.content.CursorLoader (method onStartLoading) 
     if (takeContentChanged()) { 
      forceLoad(); 
     } 
    } 
} 
0

ho preso il codice sorgente del CursorLoader dal quadro di Android, e ha scritto una classe CustomTaskLoader<T> per facilitare il lavoro.

https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/android/content/CustomTaskLoader.java

che, fondamentalmente, di implementare queste due funzioni:

public abstract T runTaskInBackground(CancellationSignal signal); 
public abstract void cleanUp(T oldResult); 

vedere l'utilizzo nelle attività e frammenti, per esempio questo: (bene il mio codice solo ignora la CancellationSignal, è un TODO nella mia lista, ma sei libero di usarlo.)

https://github.com/Palatis/danbooru-gallery-android/blob/new_api/DanbooruGallery/src/main/java/tw/idv/palatis/danboorugallery/PostListFragment.java

return new CustomTaskLoader<Cursor>(getActivity().getApplicationContext()) 
{ 
    @Override 
    public Cursor runTaskInBackground(CancellationSignal signal) 
    { 
     return SiteSession.getAllPostsCursor(PostListAdapter.POST_COLUMNS); 
    } 

    @Override 
    public void cleanUp(Cursor oldCursor) 
    { 
     if (!oldCursor.isClosed()) 
      oldCursor.close(); 
    } 
} 
0

Ho avuto lo stesso problema dopo la migrazione da CursorLoader a AsyncTaskLoader.

documentation says: sottoclassi di Loader<D> generalmente devono attuare almeno onStartLoading(), onStopLoading(), onForceLoad(), e onreset().

AsyncTaskLoader estende Loader ma non implementa onStartLoading(), onStopLoading(), onreset(). Devi implementarlo da solo!

@ davidshen84 ha proposto una buona soluzione. Ho solo aggiunto il controllo per takeContentChanged.

@Override 
protected void onStartLoading() { 
    try { 
     if (data != null) { 
      deliverResult(data); 
     } 
     if (takeContentChanged() || data == null) { 
      forceLoad(); 
     } 

     Log.d(TAG, "onStartLoading() "); 
    } catch (Exception e) { 
     Log.d(TAG, e.getMessage()); 
    } 
} 

Utilizzare forceLoad() è ok (non è una cattiva pratica). Vedere quale documentazione says:
Generalmente si dovrebbe chiamare solo quando il caricatore è avviato, ovvero, isStarted() restituisce true.

Problemi correlati