9

我有一个ViewPager(extends FragmentPagerAdapter) 包含两个Fragments. 当我在它们之间滑动时,我需要的是ListView为每个刷新一个。Fragment为此,我实现了ViewPager.OnPageChangeListener接口(即onPageScrollStateChanged)。为了保存对Fragments 的引用,我使用了HashTable. 我在方法中存储对Fragmentsin的引用:HashTablegetItem()

  @Override
        public Fragment getItem(int num) {
            if (num == 0) {
                Fragment itemsListFragment = new ItemsListFragment();
                mPageReferenceMap.put(num, itemsListFragment);
                return itemsListFragment;
            } else {
                Fragment favsListFragment = new ItemsFavsListFragment();
                mPageReferenceMap.put(num, favsListFragment);
                return favsListFragment;
            }
        }

因此,当我从一个滑动Fragment到另一个onPageScrollStateChanged触发器时,我使用HashTable在两个触发器中调用所需的方法Fragments(刷新):

 public void refreshList() {
        ((ItemsListFragment) mPageReferenceMap.get(0)).refresh();
        ((ItemsFavsListFragment) mPageReferenceMap.get(1)).refresh();
    }

一切都很好,直到orientation change事件发生。之后是refresh()方法中的代码,即:

public void refresh() {
        mAdapter.changeCursor(mDbHelper.getAll());
        getListView().setItemChecked(-1, true); // The last row from a exception trace finishes here (my class).
    }

结果IllegalStateException

java.lang.IllegalStateException: Content view not yet created
        at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
        at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
        at ebeletskiy.gmail.com.passwords.ui.ItemsFavsListFragment.refresh(ItemsFavsListFragment.java:17)

假设Content确实没有创建视图,我将方法中的boolean变量设置为并使用条件来调用或不调用,这表明活动和内容视图已成功创建。onActivityCreated()trueif/elsegetListView()

然后我正在调试以查看何时FragmentPagerAdapter调用getItem()并且发生orientation change事件后未调用该方法。所以看起来它ViewPager包含对 old 的引用Fragments。这只是我的假设。

那么,有没有办法强制再次ViewPager调用getItem(),所以我可以使用对 current 的正确引用Fragments?可能是其他一些解决方案?非常感谢你。

4

3 回答 3

5

然后我正在调试以查看 FragmentPagerAdapter 何时调用 getItem() 并且它发生在方向更改事件之后没有调用该方法。所以看起来 ViewPager 包含对旧片段的引用。

片段应该自动重新创建,就像任何片段都在配置更改中一样。例外情况是,如果您使用setRetainInstance(true)了 ,在这种情况下,它们应该是与以前相同的片段对象。

那么,有没有办法强制 ViewPager 再次调用 getItem() ,这样我就可以使用对当前片段的正确引用?

那里的碎片有什么问题?

于 2012-09-03T22:11:53.097 回答
0

我花了几天的时间寻找这个问题的解决方案,并且发现了很多要点:

  • 使用FragmentPagerAdapter而不是FragmentStatePagerAdapter

  • 使用FragmentStatePagerAdapter而不是FragmentPagerAdapter

  • 返回FragmentPagerAdapterPOSITION_NONEgetItemPosition覆盖

  • 如果您需要动态更改 Fragment,请不要使用 FragmentPagerAdapter

  • 还有很多很多很多其他...

在我的应用程序中,比如Eugene,我自己管理创建片段的实例。我将它保存在HashMap<String,Fragment>某个专门的类中,因此片段永远不会被释放,从而加快了我的应用程序(但消耗了更多资源)。

问题是当我旋转我的平板电脑(和手机)时。该getItem(int)片段不再被调用,我无法更改它。

我真的花了很多时间才真正找到解决方案,所以我需要与 StackOverflow 社区分享,他们帮助了我很多次......

这个问题的解决方案,虽然很难找到,但很简单:

只需在 FragmentPagerAdapter 的构造函数中保留对 FragmentManager 的引用即可:

public class Manager_Pager extends FragmentPagerAdapter {

    private final FragmentManager mFragmentManager;
    private final FragmentActivity mContext;

    public Manager_Pager(FragmentActivity context) {

        super( context.getSupportFragmentManager() );

        this.mContext = context;
        this.mFragmentManager = context.getSupportFragmentManager();
    }

    @Override
    public int getItemPosition( Object object ) {

// here, check if this fragment is an instance of the
//   ***FragmentClass_of_you_want_be_dynamic***

        if (object instanceof FragmentClass_of_you_want_be_dynamic) {

// if true, remove from ***FragmentManager*** and return ***POSITION_NONE***
//   to force a call to ***getItem***

            mFragmentManager.beginTransaction().remove((Fragment) object).commit();
            return POSITION_NONE;
        }

        //don't return POSITION_NONE, avoid fragment recreation.
        return super.getItemPosition(object);
    }

    @Override
    public Fragment getItem( int position ) {


        if ( position == MY_DYNAMIC_FRAGMENT_INDEX){

            Bundle args = new Bundle();
            args.putString( "anything", position );
            args.putString( "created_at", ALITEC.Utils.timeToStr() );

            return Fragment.instantiate( mContext, FragmentClass_of_you_want_be_dynamic.class.getName(), args );

        }else

        if ( position == OTHER ){

            //...

        }else

        return Fragment.instantiate( mContext, FragmentDefault.class.getName(), null );

    }
}

就这样。它会像一个魅力......

于 2014-07-08T03:57:03.910 回答
0

您可以清除保存的实例状态

    protected void onCreate(Bundle savedInstanceState) {
        clearBundle(savedInstanceState);
        super.onCreate(savedInstanceState, R.layout.activity_car);
    }


    private void clearBundle(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            savedInstanceState.remove("android:fragments");
            savedInstanceState.remove("android:support:fragments");
            savedInstanceState.remove("androidx.lifecycle.BundlableSavedStateRegistry.key");
            savedInstanceState.remove("android:lastAutofillId");
        }
    }
于 2021-03-06T21:40:00.183 回答