Android的AsyncTaskLoader不启动loadInBackground?
我想在Android上实现一个加载器的例子,但无法启动加载器。 我正在使用下面的代码。 它会打“创build加载程序”,但它永远不会到达“加载启动”日志消息。 我错过了我需要的电话吗?
活动:
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"); } }
我有使用兼容性库相同的问题。 我通过调用forceLoad
来解决它
getLoaderManager().initLoader(0, null, this).forceLoad();
很显然,关于AsyncLoader的文档是缺乏的,HoneyComb也存在这个问题。 更多信息可以在这里find
AsyncTaskLoader的官方示例也是调用forceLoad(),所以它不是一个bug,但我仍然认为这种行为不是很直观。
重写loadInBackground()
是不够的。
看看http://developer.android.com/reference/android/content/AsyncTaskLoader.html上的;AppListLoader
。
至less将这两个方法添加到您的加载器:
@Override protected void onStartLoading() { if (takeContentChanged()) forceLoad(); } @Override protected void onStopLoading() { cancelLoad(); }
并从其构造函数中调用onContentChanged()
。
rrayst的build议是相当紧凑的。 如果你这样写你的方法:
protected void onStartLoading() { forceLoad(); }
你会注意到,当一个孩子的活动出现,然后你回到父母, onStartLoading
(和loadInBackground
)再次被调用!
你能做什么? 在构造函数中设置一个内部variables( mContentChanged
)为true; 然后在onStartLoading
检查这个variables。 只有当这是真的,开始加载真实:
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(); } } @Override protected void onStopLoading() { cancelLoad(); } }
既然这里的答案(除了被接受的答案)都没有帮助我解决这个问题,那么这就是我的工作方式。
我不认为接受的答案是正确的解决scheme,因为它会导致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(); } }
如果您正在使用自定义加载程序,则可以保存最后的数据引用,并通过获取程序使其可用。 当用户旋转他的屏幕时,可以从getLoaderManager()。getLoader方法获取加载器,然后返回引用。 对于我的testing,我注意到startLoadering一直到CustomLoader.onLoadFinished,但结果永远不会传递给activity.onLoadFinished.I怀疑活动引用在循环中丢失。 顺便说一下,创build加载器的好处是通过LoaderManager持久化。 把它想象成另一种无头碎片的味道..哈哈。
Loader loader = getLoaderManager().getLoader(LOADER_ID); if( loader == null ) { getLoaderManager().initLoader(LOADER_ID, null, MyActivity.this ); } else { listAdapter.addAll(((CustomLoader) loader).getLastData()); }
我发现上面的每个解决scheme都有问题,特别是当应用程序在屏幕closures时启动,加载需要一些时间。
这是我的解决scheme(基于此 ):
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; } }