Android 从ViewPager中销毁项目';屏幕方向改变后的s适配器
因此,在屏幕方向更改后,我无法从Android 从ViewPager中销毁项目';屏幕方向改变后的s适配器,android,android-viewpager,android-pageradapter,fragmentstatepageradapter,Android,Android Viewpager,Android Pageradapter,Fragmentstatepageradapter,因此,在屏幕方向更改后,我无法从ViewPager中销毁(删除)一页。我将试着在下面几行中描述这个问题 我正在使用FragmentStatePagerAdapter作为ViewPager的适配器和一个小界面,它描述了无休止的ViewPager应该如何工作。其背后的想法是,您可以向右滚动,直到到达查看页面的末尾。如果可以从API调用加载更多结果,则会显示一个进度页,直到结果出来 在这之前一切都很好,现在问题来了。如果在此加载过程中,我旋转屏幕(这不会影响API调用,该调用基本上是一个AsyncTa
ViewPager
中销毁(删除)一页。我将试着在下面几行中描述这个问题
我正在使用FragmentStatePagerAdapter
作为ViewPager
的适配器和一个小界面,它描述了无休止的ViewPager应该如何工作。其背后的想法是,您可以向右滚动,直到到达查看页面的末尾。如果可以从API调用加载更多结果,则会显示一个进度页,直到结果出来
在这之前一切都很好,现在问题来了。如果在此加载过程中,我旋转屏幕(这不会影响API调用,该调用基本上是一个AsyncTask
),当调用返回时,应用程序崩溃,出现以下异常:
E/AndroidRuntime(13471): java.lang.IllegalStateException: Fragment ProgressFragment{42b08548} is not currently in the FragmentManager
E/AndroidRuntime(13471): at android.support.v4.app.FragmentManagerImpl.saveFragmentInstanceState(FragmentManager.java:573)
E/AndroidRuntime(13471): at android.support.v4.app.FragmentStatePagerAdapter.destroyItem(FragmentStatePagerAdapter.java:136)
E/AndroidRuntime(13471): at mypackage.OutterFragment$PagedSingleDataAdapter.destroyItem(OutterFragment.java:609)
在对库的代码进行一点挖掘之后,在这种情况下,片段的mIndex
数据字段似乎小于0
,这引发了该异常
以下是寻呼机适配器的代码:
static class PagedSingleDataAdapter extends FragmentStatePagerAdapter implements
IEndlessPagerAdapter {
private WeakReference<OutterFragment> fragment;
private List<DataItem> data;
private SparseArray<WeakReference<Fragment>> currentFragments = new SparseArray<WeakReference<Fragment>>();
private ProgressFragment progressElement;
private boolean isLoadingData;
public PagedSingleDataAdapter(SherlockFragment fragment, List<DataItem> data) {
super(fragment.getChildFragmentManager());
this.fragment = new WeakReference<OutterFragment>(
(OutterFragment) fragment);
this.data = data;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object item = super.instantiateItem(container, position);
currentFragments.append(position, new WeakReference<Fragment>(
(Fragment) item));
return item;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
@Override
public Fragment getItem(int position) {
if (isPositionOfProgressElement(position)) {
return getProgessElement();
}
WeakReference<Fragment> fragmentRef = currentFragments.get(position);
if (fragmentRef == null) {
return PageFragment.newInstance(args); // here I'm putting some info
// in the args, just deleted
// them now, not important
}
return fragmentRef.get();
}
@Override
public int getCount() {
int size = data.size();
return isLoadingData ? ++size : size;
}
@Override
public int getItemPosition(Object item) {
if (item.equals(progressElement) && !isLoadingData) {
return PagerAdapter.POSITION_NONE;
}
return PagerAdapter.POSITION_UNCHANGED;
}
public void setData(List<DataItem> data) {
this.data = data;
notifyDataSetChanged();
}
@Override
public boolean isPositionOfProgressElement(int position) {
return isLoadingData && position == data.size();
}
@Override
public void setLoadingData(boolean isLoadingData) {
this.isLoadingData = isLoadingData;
}
@Override
public boolean isLoadingData() {
return isLoadingData;
}
@Override
public Fragment getProgessElement() {
if (progressElement == null) {
progressElement = new ProgressFragment();
}
return progressElement;
}
public static class ProgressFragment extends SherlockFragment {
public ProgressFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView progressView = new TextView(container.getContext());
progressView.setGravity(Gravity.CENTER_HORIZONTAL
| Gravity.CENTER_VERTICAL);
progressView.setText(R.string.loading_more_data);
LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT);
progressView.setLayoutParams(params);
return progressView;
}
}
}
现在,还值得一提的是,API调用在交付结果之后做了什么。以下是回调:
@Override
public boolean onTaskSuccess(Context arg0, List<DataItem> result) {
data = result;
pagerAdapter.setLoadingData(false);
pagerAdapter.setData(result);
activity.invalidateOptionsMenu();
return true;
}
现在总结一下,问题是:
如果我尝试在实例化并销毁并重新创建活动(屏幕方向已更改)后从ViewPager
中删除进度元素,则会出现上述异常(由于承载pagerAdapter
的OutterFragment
未被销毁,因此它内部的所有内容都保持不变,引用等。因为承载pagerAdapter
的OutterFragment
仅与活动分离,然后重新连接).也许碎片管理器会发生一些事情,但我真的不知道是什么
我已经尝试过的:
尝试使用另一种技术删除我的进度片段,即在ontasksucces()
回调上,我尝试从片段管理器中删除该片段,但没有成功
我还试图隐藏progress元素,而不是从片段管理器中完全删除它。这起到了50%的效果,因为视图不再存在,但我有一个空页面,所以这不是我真正想要的
在屏幕方向更改后,我还尝试(重新)将progressFragment
附加到片段管理器,这也不起作用
我还尝试在重新创建活动后删除进度片段,然后再次将其添加到片段管理器中,但没有成功
试图从ontasksucces()
回调手动调用destroyItem()
(非常非常难看),但没有成功
抱歉,伙计们发了这么长的帖子,但我正试图尽可能地解释这个问题,以便你们能够理解
如有任何解决方案,敬请推荐
谢谢
更新:找到解决方案
好的,这需要一段时间。问题是在进度片段上调用了destroyItem()回调两次,一次是在屏幕方向更改时,另一次是在api调用完成后。这就是异常的原因。我找到的解决方案如下:
继续跟踪api调用是否完成,并销毁进度片段(在本例中,代码如下)
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (object.equals(progressElement) && apiCallFinished == true) {
apiCallFinished = false;
currentFragments.put(position, currentFragments.get(position + 1));
super.destroyItem(container, position, object);
} else if (!(object.equals(progressElement))) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (object.equals(progressElement) && apiCallFinished == true) {
apiCallFinished = false;
currentFragments.put(position, currentFragments.get(position + 1));
super.destroyItem(container, position, object);
} else if (!(object.equals(progressElement))) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
}
然后在适配器的构造函数中将此apiCallFinished设置为false,在ontasksucces()
回调中将其设置为true。
它真的很有效!更新:解决方案找到了正常,所以这需要一段时间。问题是destroyItem()对进度片段调用了两次回调,一次是在屏幕方向更改时,然后在api调用完成后再次调用。这就是为什么会出现异常。我找到的解决方案如下:继续跟踪api调用是否完成,并销毁进度片段。在本例中,代码如下
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (object.equals(progressElement) && apiCallFinished == true) {
apiCallFinished = false;
currentFragments.put(position, currentFragments.get(position + 1));
super.destroyItem(container, position, object);
} else if (!(object.equals(progressElement))) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (object.equals(progressElement) && apiCallFinished == true) {
apiCallFinished = false;
currentFragments.put(position, currentFragments.get(position + 1));
super.destroyItem(container, position, object);
} else if (!(object.equals(progressElement))) {
currentFragments.put(position, null);
super.destroyItem(container, position, object);
}
}
然后在适配器的构造函数中将此apiCallFinished设置为false,在onTaskSuccess()中将其设置为true回调。这真的很有效!也许是个愚蠢的问题,但在旋转屏幕后,您是否真的将片段重新添加到viewPager?您的活动在方向更改时会被破坏。啊,很好,是的,我正在添加片段,但忘了添加代码:)。谢谢你指出这一点,我将编辑一点我的帖子。干杯使用onCreate上的.addTab()再次尝试实际添加选项卡。您的问题只是progressFragment,还是其他问题?问题就在于这个progressFragment,我对其他页面没有其他问题,这些页面都是PagerFragment实例。但是,你的建议实际上是不可能的,因为我没有使用TabsAdapter,因此没有addTab()方法,但是谢谢你的建议。啊,很抱歉,我只更新我的帖子,所以setLoadingTrue()是在onPageSelected()中完成的如果需要新数据,即如果视图寻呼机已到达末尾,但仍然可以从api获取数据,则回调。谢谢你的建议,事实并非如此,我找到了答案,干杯!