Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/229.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 从ViewPager中销毁项目';屏幕方向改变后的s适配器_Android_Android Viewpager_Android Pageradapter_Fragmentstatepageradapter - Fatal编程技术网

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获取数据,则回调。谢谢你的建议,事实并非如此,我找到了答案,干杯!