2016-11-23 58 views
6

我有我的ViewPagerOffscreenPageLimit=2(容易重现我的错误)6页。
6页中的所有数据都来自服务器。在onCreateView中,我向服务器发送请求,并在从服务器获取数据时刷新UI。片段创建/恢复重复的数据视图时重新连接

当我选择第一个选项卡并更改持续快速几次,一些寻呼机显示错误。而在那个时候,我的字段mMainLayout在片段中不为空。

例如,我在第一页有ListView。当页面出错时,另一个ListView位于右侧顶部ListView。当我尝试滚动ListView时,只有正确的一个(底部)移动。

我知道,我的回答听众持有mMainLayout和其他一些意见的参考,我在方法onCreateView创建一个新的mMainLayout,我以为片段使用新mMainLayout当它重新连接/恢复和放下旧的(或从容器中取出)。但是我错了。

我知道FragmentPagerAdapterinstantiateItem上附加/重新附加片段,并在destroyItem中分离。适配器没有删除一个片段。适配器没有创建新的片段。片段保持视图和视图状态本身。

我从容器中取出mMainLayoutonDestroyView设置在我的片段空所有的意见,并保存在没有onSaveInstanceState。但仍然容易重现该错误。

活动:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    registerReceiver(receiver, new IntentFilter("com.souyidai.intent.action.log_fragment")); 
    FragmentManager fragmentManager = getFragmentManager(); 
    mResources = getResources(); 
    mMainPagerAdapter = new MainPagerAdapter(fragmentManager); 
    mPager = (ViewPager) findViewById(R.id.pager); 
    mPager.setAdapter(mMainPagerAdapter); 
    mPager.setOffscreenPageLimit(CACHE_SIZE); 
    mIndicator = (TabPageIndicator) findViewById(R.id.indicator); 
    mIndicator.setViewPager(mPager); 
    ... 
} 

private class MainPagerAdapter extends FragmentPagerAdapter { 
    public MainPagerAdapter(FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     MainConfig.TabItem tab = mTabs.get(position); 
     String tabType = tab.getTabType(); 
     String code = tab.getCode(); 
     MainConfig.TabItem.SubTabItem subTabItem = tab.getSubitem().get(0); 
     Fragment fragment = MainFragment.newInstance(code, subTabItem); 
     return fragment; 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 
     MainConfig.TabItem tab = mTabs.get(position); 
     return tab.getTitle(); 
    } 

    @Override 
    public int getCount() { 
     return mTabs.size(); 
    } 
} 

片段:

​​

android.support.v13.app.FragmentPagerAdapter

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    if (mCurTransaction == null) { 
     mCurTransaction = mFragmentManager.beginTransaction(); 
    } 

    final long itemId = getItemId(position); 

    // Do we already have this fragment? 
    String name = makeFragmentName(container.getId(), itemId); 
    Fragment fragment = mFragmentManager.findFragmentByTag(name); 
    if (fragment != null) { 
     if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); 
     mCurTransaction.attach(fragment); 
    } else { 
     fragment = getItem(position); 
     if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); 
     mCurTransaction.add(container.getId(), fragment, 
       makeFragmentName(container.getId(), itemId)); 
    } 
    if (fragment != mCurrentPrimaryItem) { 
     FragmentCompat.setMenuVisibility(fragment, false); 
     FragmentCompat.setUserVisibleHint(fragment, false); 
    } 

    return fragment; 
} 

我发现这一点:

Android fragment onCreateView creating duplicate views on top of each other

但我只在FragmentPagerAdapter.getItem创造新的片段。所以我们不同。

我通过去除所有儿童mMainLayout如果mMainLayout不是方法onCreateView空解决这个问题。然后一切都很好。但我仍然对这个错误发生的原因感到困惑。

我做了一些测试。
1.尝试添加一个片段两次,应用程序崩溃和日志说:java.lang.IllegalStateException:已添加片段:...
2。尝试附加片段的两倍,系统不叫Fragment.onCreateFragment.onCreateView

+0

请加你的代码 –

+0

使用'setRetainInstance(true)'片段的api如果你想保留你的片段状态。 在第二次加载同一个片段时,如果它是在内存中,它将从之前的实例加载UI组件,否则将创建新的片段。 因此,您不需要在ondestroyview方法中使所有UI组件空。 –

+0

@ keyur9779我不想保留我的片段状态。但它看起来像片段仍然从以前恢复状态。 –

回答

3

发生这种情况由于instantiateItem() 有一件事我已经注意到自定义实现。你正在搞乱检查是否已经添加了片段。

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    if (mCurTransaction == null) { 
     mCurTransaction = mFragmentManager.beginTransaction(); 
    } 

    final long itemId = getItemId(position); 

    // Do we already have this fragment? 
    String name = makeFragmentName(container.getId(), itemId); 
    Fragment fragment = mFragmentManager.findFragmentByTag(name); 
    if (fragment != null) { 
     if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); 
     //make sure you are not attaching already added fragment 
     //try with comment and uncomment two lines below 
     //if(!fragment.isAdded()) 
     //mCurTransaction.attach(fragment); 
    } else { 
     fragment = getItem(position); 
     if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); 
     mCurTransaction.add(container.getId(), fragment, 
       makeFragmentName(container.getId(), itemId)); 
    } 
    if (fragment != mCurrentPrimaryItem) { 
     FragmentCompat.setMenuVisibility(fragment, false); 
     FragmentCompat.setUserVisibleHint(fragment, false); 
    } 

    return fragment; 
} 

不知道为什么要创建类的成员领域mMainLayout

//try to go with default 
View view = inflater.inflate(R.layout.fragment_main, container, false); 

建议你学习this

+0

如果我添加一个片段两次,应用程序崩溃和日志说:java.lang.IllegalStateException:片段已添加:... –

+0

你是对的,没有必要持有mMainLayout的引用。但是我必须持有一些视图参考,以便在从服务器获取数据时更新视图。 –

+0

我的应用程序没有崩溃,所以我认为没有任何帮助可以调用fragment.isAdded –

2

你可以用代码试试,我面临着类似的问题得到了解决同波纹管变化。在这种情况下,不需要使所有onDestroyView中的引用都为空。因为在这种情况下,您需要在代码中的任何其他位置使用这些引用之前始终进行空值检查。

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    if(mMainLayout == null) 
    { 
     mMainLayout = inflater.inflate(R.layout.fragment_main, container,false); 
... 
    } 
    return mMainLayout; 
} 

mMainlayout不为空,这意味着你的片段实例已具有mMainLayout的一个实例,已添加到ViewGroup container不需要重新添加。由于您正在向同一个容器添加相同的视图,因此您面临问题。

+0

我最后在我的问题中提到我解决了与您相同的问题。我想知道为什么视图/片段被添加两次。 –

+0

由于您的ViewGroup容器中已经添加了相同的布局,因此我们需要进行空检查以避免两次添加。 – Swapnil

相关问题