AsyncTaskLoader не запускается
Я хочу реализовать AsyncTaskLoader в своем проекте с помощью пакета Compatibility Package, поэтому я выполнил руководство Loader в Android Docs.
Проблема в том, что Loader ничего не делает, кажется, что loadInBackground()
никогда не называется
Любая идея о том, что неправильно в моем коде?
(ExpandableListFragment
extends Fragment
, но не переопределяет какой-либо критический метод)
Спасибо: -)
/** EDIT:
Я понял (поздно, я идиот), что AsyncTaskLoader является абстрактным классом, поэтому мне нужно подклассифицировать его... m (__) m
Я оставляю вопрос на случай, если кто-то зайдет за мной, кто знает...
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);
}
}
Ответы
Ответ 1
Я думаю, что лучшим решением для пакета Compatibility является переопределение метода AsyncTaskLoader.onStartLoading.
например.
@Override
protected void onStartLoading() {
if(dataIsReady) {
deliverResult(data);
} else {
forceLoad();
}
}
Ответ 2
Это точно исправление, но оно должно работать. Я уверен, что библиотека совместимости нарушена. Попробуйте следующее:
getLoaderManager().initLoader(0, null, this).forceLoad();
Ответ 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 how we start every AsyncTaskLoader...
// - code snippet from android.content.CursorLoader (method onStartLoading)
if (takeContentChanged()) {
forceLoad();
}
}
}
Ответ 4
Глядя на обсуждение https://code.google.com/p/android/issues/detail?id=14944, проверка на takeContentChanged
также является важным шагом.
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
Ответ 5
Я взял исходный код CursorLoader
из фреймворка android и написал класс 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
, это a 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();
}
}
Ответ 6
У меня была такая же проблема после перехода с CursorLoader на AsyncTaskLoader.
документация говорит: подклассы Loader<D>
обычно должны реализовывать не менее onStartLoading(), onStopLoading(), onForceLoad(), и onReset().
AsyncTaskLoader расширяет Loader, но не реализует 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() в порядке (не плохая практика). Посмотрите, какая документация говорит:
Обычно вы должны вызывать это только при запуске загрузчика - то есть isStarted() возвращает true.
Ответ 7
У меня все еще была проблема, что загрузка данных не вызывалась. Наконец, я удалил AsyncTaskLoader (версия библиотеки поддержки) и использовал только AsyncTask (не из библиотеки поддержки) для выполнения задания. И это сработало.
Этого может быть достаточно для ваших нужд.
Описание и пример: http://developer.android.com/reference/android/os/AsyncTask.html.
Вам нужно расширить класс AsyncTask.
Метод doInBackground выполнит работу, а в методе onPostExecute вы получите результат. Для запуска AsyncTask вы вызываете метод выполнить на свой экземпляр. См. Ссылку.