Android AsyncTaskLoader не запускает loadInBackground?
Я пытаюсь реализовать пример загрузчика на Android, но не могу заставить его запустить загрузчик. Я использую следующий код. Он попадет в "Create Loader", но он никогда не достигнет сообщения журнала "Загрузка начата". Мне не хватает звонка, который мне нужен?
Активность:
public class TestingZoneActivity extends ListActivity implements LoaderCallbacks<ArrayList<Content>>{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<ArrayList<Content>> onCreateLoader(int id, Bundle args) {
Log.e("TEST", "Create Loader");
return new ImageLoader(this);
}
@Override
public void onLoadFinished(Loader<ArrayList<Content>> loader, ArrayList<Content> data) {
setListAdapter(new ImageAdapter(this, data));
}
@Override
public void onLoaderReset(Loader<ArrayList<Content>> loader) {
setListAdapter(null);
}
}
Погрузчик:
public class ImageLoader extends AsyncTaskLoader<ArrayList<Content>> {
public ImageLoader(Context context) {
super(context);
}
@Override
public ArrayList<Content> loadInBackground() {
Log.e("TEST", "Loading started");
}
}
Ответы
Ответ 1
У меня была такая же проблема с использованием библиотеки совместимости.
Я решил это, позвонив forceLoad
getLoaderManager().initLoader(0, null, this).forceLoad();
Очевидно, что документация по AsyncLoader отсутствует, и эта проблема также существует в HoneyComb. Более подробную информацию можно найти здесь
Официальный пример AsyncTaskLoader также вызывает forceLoad(), поэтому он не является ошибкой, но я все же считаю, что это поведение не очень интуитивное.
Ответ 2
Переопределить loadInBackground()
недостаточно.
Посмотрите AppListLoader
на http://developer.android.com/reference/android/content/AsyncTaskLoader.html.
По крайней мере, добавьте эти два метода в ваш загрузчик:
@Override
protected void onStartLoading() {
if (takeContentChanged())
forceLoad();
}
@Override
protected void onStopLoading() {
cancelLoad();
}
и вызовите onContentChanged()
из своего конструктора.
Ответ 3
rrayst советы довольно компактны. Если вы напишете свой метод следующим образом:
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();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
}
Ответ 4
Поскольку ни один из ответов здесь (кроме принятого) не помог мне решить это, вот как это сработало для меня.
Я не думаю, что принятый ответ является правильным решением, так как он вызывает loadInBackground()
более часто, чем необходимо, т.е. при изменении ориентации, чего не происходит, когда должным образом переопределяет следующие методы в загрузчике
@Override
public void deliverResult(final List<Participant> data) {
participants = data;
if (isStarted()) {
super.deliverResult(data);
}
}
@Override
protected void onStartLoading() {
if (takeContentChanged() || participants == null) {
forceLoad();
}
}
Ответ 5
Если вы используете пользовательский загрузчик, вы можете сохранить последнюю ссылку на данные и получить ее через геттер. когда пользователь поворачивает свой экран, вы можете вернуть загрузчика из метода getLoaderManager(). getLoader, а затем вернуть ссылку. Для моего тестирования я заметил, что startLoadering доходит до CustomLoader.onLoadFinished, но результат никогда не доставляется в activity.onLoadFinished. Я подозреваю, что ссылка на активность теряется при ротации. Кстати, великое дело в создании загрузчиков - они упорны через LoaderManager. Подумайте об этом как о другом аромате безголовых обломков.. lol.
Loader loader = getLoaderManager().getLoader(LOADER_ID);
if( loader == null )
{
getLoaderManager().initLoader(LOADER_ID, null, MyActivity.this );
}
else
{
listAdapter.addAll(((CustomLoader) loader).getLastData());
}
Ответ 6
Я обнаружил, что каждое из вышеперечисленных решений имеет проблемы, особенно когда приложение запускается, когда экран выключен, а загрузка занимает несколько секунд.
Здесь мое решение (база this):
public abstract class AsyncTaskLoaderEx<T> extends AsyncTaskLoader<T> {
private static final AtomicInteger sCurrentUniqueId = new AtomicInteger(0);
private T mData;
public boolean hasResult = false;
public static int getNewUniqueLoaderId() {
return sCurrentUniqueId.getAndIncrement();
}
public AsyncTaskLoaderEx(final Context context) {
super(context);
onContentChanged();
}
@Override
protected void onStartLoading() {
if (takeContentChanged())
forceLoad();
else if (hasResult)
deliverResult(mData);
}
@Override
public void deliverResult(final T data) {
mData = data;
hasResult = true;
super.deliverResult(data);
}
@Override
protected void onReset() {
super.onReset();
onStopLoading();
if (hasResult) {
onReleaseResources(mData);
mData = null;
hasResult = false;
}
}
protected void onReleaseResources(T data) {
//nothing to do.
}
public T getResult() {
return mData;
}
}