我使用AsyncTaskLoader从数据库查询加载游标。 我关注Android Developers示例: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
但不知何故,在此片段(使用加载器)之后添加到页面适配器的片段不会附加到活动上,并且当它尝试使用需要活动的方法(如getString())时被抛出并说这个片段没有附加到任何活动。
以下是一些代码:
将片段添加到页面适配器。
mAdapter = new PlaceFragmentPagerAdapter(getSupportFragmentManager());
NewFragment newFrag = new NewFragment();
mAdapter.addFragment(newShiftFrag);
ListFragment listFrag = new ListFragment();
mAdapter.addFragment(listFrag);
SettingsFragment settingsFrag = new SettingsFragment();
mAdapter.addFragment(settingsFrag);
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
AsyncTaskLoader实现:
抽象公共类AbstractCursorLoader扩展了AsyncTaskLoader {
abstract protected Cursor buildCursor();
Cursor lastCursor=null;
public AbstractCursorLoader(Context context) {
super(context);
}
/**
* Runs on a worker thread, loading in our data. Delegates
* the real work to concrete subclass' buildCursor() method.
*/
@Override
public Cursor loadInBackground() {
Cursor cursor=buildCursor();
if (cursor!=null) {
// Ensure the cursor window is filled
cursor.getCount();
}
return(cursor);
}
/**
* Runs on the UI thread, routing the results from the
* background thread to whatever is using the Cursor
* (e.g., a CursorAdapter).
*/
@Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor!=null) {
cursor.close();
}
return;
}
Cursor oldCursor=lastCursor;
lastCursor=cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor!=null && oldCursor!=cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Starts an asynchronous load of the list data.
* When the result is ready the callbacks will be called
* on the UI thread. If a previous load has been completed
* and is still valid the result may be passed to the
* callbacks immediately.
*
* Must be called from the UI thread.
*/
@Override
protected void onStartLoading() {
if (lastCursor!=null) {
deliverResult(lastCursor);
}
if (takeContentChanged() || lastCursor==null) {
forceLoad();
}
}
/**
* Must be called from the UI thread, triggered by a
* call to stopLoading().
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Must be called from the UI thread, triggered by a
* call to cancel(). Here, we make sure our Cursor
* is closed, if it still exists and is not already closed.
*/
@Override
public void onCanceled(Cursor cursor) {
if (cursor!=null && !cursor.isClosed()) {
cursor.close();
}
}
/**
* Must be called from the UI thread, triggered by a
* call to reset(). Here, we make sure our Cursor
* is closed, if it still exists and is not already closed.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (lastCursor!=null && !lastCursor.isClosed()) {
lastCursor.close();
}
lastCursor=null;
}
}
private static class ListLoader extends AbstractCursorLoader {
private String mName;
public ShiftsListLoader(Context context, String name) {
super(context);
mName = name;
}
@Override
protected Cursor buildCursor() {
PlacesHandler wph = new PlacesHandler(this.getContext());
return wph.GetShifts(mName);
}
}
初始化加载程序:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
// TODO change to resource and back
setEmptyText("Nothing here..");
// Start out with a progress indicator.
setListShown(false);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new ListLoader(getActivity(), mWorkPlaceName);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Create an empty adapter we will use to display the loaded data.
mAdapter = new ListCursorAdapter(getActivity(), data, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(mAdapter);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// TODO Auto-generated method stub
}
我真的不知道为什么会这样。
P.S。我在评论中制作代码块时遇到了一些问题,我发现它有一个bug,很抱歉。
提前谢谢,Elad。
答案 0 :(得分:2)
简短的回答是,在收到适当的生命周期回调信号之前,你永远不应该假设某个片段处于任何特定状态。
您所看到的是在ViewPager利用的ICS期间添加的优化。 FragmentPagerAdapter通过调用setUserVisibleHint特别标记屏幕外片段,因为用户不可见。 FragmentManager使用它来优先处理加载器的执行方式,以便用户首先看到完全加载的可见页面,加载侧页不会减慢加载可见页面的过程。具体来说,它会延迟将片段移动到“已启动”状态,也就是当加载器开始运行时。
如果用户在此过程中滚动到另一个页面,FragmentManager会将片段移动到启动状态并立即开始运行其加载器作为FragmentPagerAdapter#setPrimaryItem()的一部分,因为此方法将当前页面标记为现在用户可见。