2

我的 Android 应用程序有一个单独的活动,其中一个选项卡控制器托管 4 个选项卡——每个选项卡都由一个片段表示。当我在运行 OS 4.03 的测试设备上运行该应用程序时,该应用程序可以运行,并且我可以导航到不同的选项卡等。当该应用程序在具有 OS 4.3 的设备上运行时,该应用程序在启动期间崩溃并出现 IllegalStateException: Fragment already added :MyFirstTabFragment。

这是堆栈跟踪:

java.lang.IllegalStateException:片段已添加:MyFirstTabFragment{41866dc0 #0 id=0x7f080000 MyFirstTabFragment} at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1128) at android.app.BackStackRecord.run(BackStackRecord.java:616)在 android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435) 在 android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:474) 在 android.support.v13.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:167) 在android.support.v4.view.ViewPager.populate(ViewPager.java:1068) 在 android.support.v4.view.ViewPager.populate(ViewPager.java:914) 在 android.support.v4.view.ViewPager.onMeasure( ViewPager.java:1436) 在 android.view.view.measure(View.java:15848) 在 android.view。ViewGroup.measureChildWithMargins(ViewGroup.java:5012) at android.widget.FrameLayout.onMeasure(FrameLayout.java:310) at android.view.View.measure(View.java:15848) at android.view.ViewGroup.measureChildWithMargins(ViewGroup .java:5012) 在 com.android.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:302) 在 android.view.View.measure(View.java:15848) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup. java:5012) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:310) 在 com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2189) 在 android.view.View.measure (View.java:15848) 在 android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1905) 在 android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1104) 在 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1284) 在 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1004) 在 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5481) 在android.view.Choreographer$CallbackRecord.run(Choreographer.java:749) at android.view.Choreographer.doCallbacks(Choreographer.java:562) at android.view.Choreographer.doFrame(Choreographer.java:532) at android.view .Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735) 在 android.os.Handler.handleCallback(Handler.java:730) 在 android.os.Handler.dispatchMessage(Handler.java:92) 在 android.os.Looper。在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invokeNative(Native Method) 在 android.app.ActivityThread.main(ActivityThread.java:5103) 的 loop(Looper.java:137)。lang.reflect.Method.invoke(Method.java:525) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit. java:553) 在 dalvik.system.NativeStart.main(Native Method)

该问题似乎是由于尝试在我的 FragmentStatePagerAdapter 扩展类的 getItem() 方法中的 FragmentTransaction 中添加片段引起的,如下所示:

public class MyFragmentStatePagerAdapter extends android.support.v13.app.FragmentStatePagerAdapter {        

    @Override
    public Fragment getItem(int position) {
        if (position == 0) {
            Fragment fragment = new MyFirstTabFragment();
            getFragmentManager().beginTransaction().add(fragment, "MyFirstTabFragmentTag").commit();

         // getFragmentManager().beginTransaction().replace(R.id.pager, fragment, "MyFirstTabFragmentTag").commit();

            return fragment;  
        } else if (position == 1) {
            Fragment fragment = new MySecondTabFragment();
            getFragmentManager().beginTransaction().add(fragment, "MySecondTabFragmentTag").commit();

         // getFragmentManager().beginTransaction().replace(R.id.pager, fragment, "MySecondTabFragmentTag").commit();

            return fragment;  
        }
    }
.
.
.

}

我调用 add() 的原因是我可以将标签与我的片段相关联,以便稍后访问这些片段,以便在选择/取消选择选项卡时调用这些片段实例上的方法。

我搜索了有关 IllegalStateException 的各种帖子,并尝试了各种建议,包括调用 replace() 而不是 add()、调用 remove() 然后调用 add()、调用 MyFirstTabFragment.instantiate() 而不是 new MyFirstTabFragment(),这些都没有更改已纠正了问题。

我怀疑我可能在此过程中过早地执行此 FragmentTransaction,因为当我尝试使用我的标签添加或替换片段时,ViewPager 当前正在添加片段。有没有人对此过程有更好的见解?有没有更好的地方可以让这些单独的 add() 调用来标记我的片段?

在此先感谢您的任何建议!

4

4 回答 4

2

所以只是为了完成这个线程......

我删除了适配器的 getItem() 方法中的 add() 或 replace() 调用,并简单地实例化新片段以避免 IllegalStateException,但无法确定移动 replace() 调用的逻辑位置,以便我可以标记碎片。这是不幸的,因为使用标签将是最可靠的解决方案。

我尝试使用内部“android:switcher ...”标签访问片段,但这似乎不起作用 - 查看我的片段的标签,标签始终为空 - 所以也许他们将内部行为更改为 no不再默认生成标签。

我求助于维护自己的片段实例集合,这些片段实例在 getItem() 调用期间填充并在适配器的 destroyItem() 调用期间更新。我希望这里没有任何意外会导致我的集合具有与 ViewPager/adapter 存储的不同的实例。

于 2013-12-17T17:34:52.247 回答
1

只需返回适配器中的片段,getItem当您调用setAdapter.

@Override
public Fragment getItem(int position) {
    if (position == 0) {
        Fragment fragment = new MyFirstTabFragment();

        return fragment;  
    } else if (position == 1) {
        Fragment fragment = new MySecondTabFragment();

        return fragment;  
    }
}
于 2013-12-16T19:36:02.773 回答
0

你可以做这样的事情:

private Fragment[] pages = new Fragment[2];

@Override
public Fragment getItem(int position) {

     if(pages[position] == null){

        switch(position){

        case 0:
           pages[position] = new MyFirstTabFragment();
        break;

        case 1:
            pages[position] = new MySecondTabFragment();
        break:

        default:
        //you have to determine a default position
        break;
    }
  }

  return pages[position];
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    pages[position] = null;
}

因此,您可以访问适配器片段实例,只需调用:

MyFirstTabFragment firstFragment = (MyFirstTabFragment)adapter.getItem(0);

它不会为通知的位置创建另一个实例。

于 2017-10-09T20:41:01.870 回答
0

这对我们有用:

private FragmentManager fm;
private Map<Integer, Fragment> map;

@Override
public Fragment getItem(int position) {
    fm.executePendingTransactions();
    if (map == null)
        map = new HashMap<>();

    if (map.containsKey(position))
        return map.get(position);

    Fragment fragment = new Fragment();
    ...
    map.put(position, fragment);
    return fragment;
}
于 2021-06-15T01:02:24.673 回答