2011-12-22 3 views
29

Я хочу реализовать AsyncTaskLoader в своем проекте с помощью пакета Compatibility Package, поэтому я выполнил руководство по загрузке в Android Docs.AsyncTaskLoader не запускается

Проблема заключается в том, что загрузчик не делает ничего, кажется, loadInBackground() никогда не называют

Любой идеи о том, что случилось в моем коде? (ExpandableListFragment расширяет Fragment, но не отменяет любой критический метод)

Спасибо :-)

/** EDIT:

Я понял (поздно, я дебил), что AsyncTaskLoader является абстрактным классом, так что мне нужно подкласс ... м (__) м я оставляю этот вопрос в случае, если кто-то приходит сюда за мной, кто знает ...

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

Ваш 'AsyncTaskLoader', кажется, пропускает много вещей, например' deliverResults() '. У меня есть две реализации «AsyncTaskLoader» в моем проекте «LoaderEx», который вы можете изучить для сравнения: https://github.com/commonsguy/cwac-loaderex – CommonsWare

+0

Кажется, я беспорядок, и я не понимал, что это абстрактный класс ... Итак, теперь я знаю, почему я нашел несколько примеров, подклассифицирующих его. Спасибо! –

ответ

62

Я думаю, что лучшее решение для пакета обеспечения совместимости, чтобы переопределить AsyncTaskLoader.onStartLoading метода.

например.

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

Я сделал это в конце :-D. Благодаря! –

+0

Да, спасибо, Дэвид!Написал это в сообщение с исходным кодом: http://blog.blundell-apps.com/tut-asynctask-loader-using-support-library/ – Blundell

+2

Проверка на 'takeContentChanged' также кажется важным шагом. –

7

Это точно исправление, но оно должно работать. Я уверен, что библиотека совместимости нарушена. Попробуйте это:

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

Это еще один способ сделать это :-D. –

+5

Это будет работать, но, вероятно, лучше реализовать свой 'Loader ' правильно (поскольку davidshen84 предлагает, используя метод 'onStartLoading()') вместо вызова 'forceLoad()' непосредственно в вашей 'Activity' и/или 'Fragment'. –

1

Глядя на обсуждение в https://code.google.com/p/android/issues/detail?id=14944, проверяя takeContentChanged представляется важным шагом тоже.

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

Здесь нет смысла использовать 'takeContentChanged' здесь - это не повлияет на результат. Если 'mCursor' равно null, будет вызываться' forceLoad'. Если это не так - 'deliverResult' будет вызван. –

+1

Почему вы говорите, что 'takeContentChanged' не имеет смысла? http://developer.android.com/reference/android/content/AsyncTaskLoader.html Пример Google использует это. –

+0

Потому что, когда действие вводит 'onPause()' и возвращается с 'onResume()', загрузчик уведомляется и снова вызывает 'onStartLoading()'. Поэтому 'takeContentChanged()' (если 'onContentChanged()' был вызван ранее) заставит обновить 'mCursor' последними доступными изменениями. Однако при первом 'if' я бы поставил вместо этого' if (mCursor! = Null &&! TakeContentChanged()) '. – AxeEffect

-2

У меня все еще была проблема с тем, что загрузка данных не вызывалась. Я, наконец, удалил AsyncTaskLoader (версия библиотеки поддержки) и использовал только AsyncTask (не из библиотеки поддержки), чтобы выполнить эту работу. И это сработало.

Этого может быть достаточно для ваших нужд.

Описание и пример: http://developer.android.com/reference/android/os/AsyncTask.html.

Вы должны расширить класс AsyncTask.

Метод doInBackground будет делать работу и в методе onPostExecute вы получите результат. Для запуска AsyncTask вы вызываете метод , выполнив на свой экземпляр. См. Ссылку.

+1

AsyncTask и AsyncTaskLoader - это совсем другие вещи ... у AsyncTaskLoader есть несколько преимуществ. Вы должны исследовать немного больше –

3

Cheok Yan Cheng абсолютно прав:

Проверка takeContentChanged кажется важным шагом тоже.

Если вы пишете ваш метод, как это:

protected void onStartLoading() { 
    forceLoad(); 
} 

вы 'заметите, что когда ребенок деятельность приходит вверх, а затем вы вернетесь к родителю одного, onStartLoading (и так loadInBackground) называются еще раз!

Что вы можете сделать? Установите внутреннюю переменную (mContentChanged) в true внутри конструктора; затем проверьте эту переменную внутри onStartLoading. Только тогда, когда это правда, начать загрузку для реального:

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

Я взял исходный код CursorLoader от андроида рамок, и написал CustomTaskLoader<T> класс, чтобы облегчить работу.

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

вы в основном выполнять эти две функции:

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

увидеть использование в деятельности и фрагментов, например, этот: (ну мой код просто игнорирует CancellationSignal, это TODO в моем списке, но вы можете использовать его.)

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

У меня была такая же проблема после перехода с CursorLoader на AsyncTaskLoader.

documentation says: Подклассы Loader<D> как правило, должны осуществлять, по меньшей мере onStartLoading(), onStopLoading(), onForceLoad() и OnReset().

AsyncTaskLoader расширяет погрузчика, но не реализует onStartLoading(), onStopLoading(), OnReset(). Вы должны реализовать его самостоятельно!

@ davidshen84 предложил хорошее решение. Я только добавил проверку для 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()); 
    } 
} 

Использование forceLoad() в порядке (не плохая практика). Посмотрите, какая документация says:
Обычно вы должны вызывать это только при запуске загрузчика - то есть isStarted() возвращает значение true.