2016-11-23 54 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

相關問題