2016-11-23 17 views
6

Tôi có 6 trang trong số ViewPagerOffscreenPageLimit=2 (dễ tái tạo lỗi của mình).
tất cả dữ liệu trong 6 trang là từ máy chủ. Trong onCreateView, tôi gửi yêu cầu tới máy chủ và làm mới giao diện người dùng khi tôi nhận dữ liệu từ máy chủ.Phân đoạn tạo/khôi phục chế độ xem trùng lặp khi đính kèm lại

Khi tôi chọn tab đầu tiên và thay đổi để kéo dài nhanh chóng nhiều lần, một số máy nhắn tin hiển thị sai. Và tại thời điểm đó, trường của tôi mMainLayout trong phân đoạn không phải là rỗng. Ví dụ, tôi có một ListView trong trang đầu tiên của tôi. Khi trang sai, Danh sách xem khác nằm ở trên cùng bên phải Chế độ xem danh sách. Khi tôi cố gắng di chuyển ListView, chỉ di chuyển bên phải (phần dưới).

Tôi biết rằng người nghe phản ứng của tôi giữ tham chiếu của mMainLayout và một số quan điểm khác, tôi tạo ra một mới mMainLayout trong phương pháp onCreateView, tôi nghĩ đoạn sử dụng mới mMainLayout khi nó lại đính kèm/khôi phục và thả cái cũ (hoặc loại bỏ nó khỏi thùng chứa). Nhưng tôi đã sai.

Tôi biết rằng FragmentPagerAdapter đính kèm/đính kèm lại đoạn trong instantiateItem và tách ra trong destroyItem. Bộ điều hợp không xóa một đoạn. Bộ điều hợp không tạo ra một đoạn mới. Fragment giữ chế độ xem và xem trạng thái của chính nó.

Tôi xóa mMainLayout khỏi vùng chứa và đặt tất cả chế độ xem trong phân đoạn rỗng của tôi tại onDestroyView và không lưu gì trong onSaveInstanceState. Nhưng vẫn dễ tái tạo lỗi.

hoạt động:

@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(); 
    } 
} 

đoạn:

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


@Override 
public void onDestroyView() { 
    super.onDestroyView(); 
    mContainer.removeView(mMainLayout); 
    mContainer = null; 
    mMainLayout = null; 
    mSwipeRefreshLayout = null; 
    mListView = null; 
    mHeaderLayout = null; 
    mFooterLayout = null; 
    ... 
} 

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; 
} 

Tôi tìm thấy điều này:

Android fragment onCreateView creating duplicate views on top of each other

Nhưng tôi chỉ tạo đoạn mới trong FragmentPagerAdapter.getItem. Vì vậy, chúng tôi khác nhau.

tôi giải quyết việc này bằng cách loại bỏ tất cả các trẻ em của mMainLayout nếu mMainLayout không phải là null trong phương pháp onCreateView. Sau đó, mọi thứ đều ổn. Nhưng tôi vẫn còn bối rối là tại sao lỗi này lại xảy ra?

Tôi đã thực hiện một số thử nghiệm.
1. cố gắng thêm một đoạn hai lần, lỗi ứng dụng và nhật ký cho biết: java.lang.IllegalStateException: Phân đoạn đã được thêm: ...
2.cố đính kèm một đoạn hai lần, hệ thống không gọi Fragment.onCreate hoặc Fragment.onCreateView

+0

Vui lòng thêm mã của bạn –

+0

sử dụng 'setRetainInstance (true)' api of fragment Nếu bạn muốn giữ nguyên trạng thái phân đoạn của mình. Khi tải cùng một đoạn 2 lần, nó sẽ tải thành phần giao diện người dùng từ phiên bản trước nếu nó là của chúng trong bộ nhớ khác, đoạn mới sẽ được tạo. Vì vậy, bạn không cần phải làm cho tất cả các thành phần UI null trong phương thức ondestroyview. –

+0

@ keyur9779 Tôi không muốn giữ lại trạng thái phân đoạn của mình. nhưng có vẻ như mảnh đó vẫn khôi phục trạng thái từ trước đó. –

Trả lời

3

Tình huống này xảy ra do triển khai tùy chỉnh instantiateItem() Một điều tôi đã nhận thấy. Bạn đang rối tung kiểm tra xem phân đoạn đã được thêm chưa.

@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; 
} 

Không biết lý do tại sao bạn đang tạo lĩnh vực thành viên lớp cho mMainLayout

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

khuyên bạn nên nghiên cứu this

+0

Nếu tôi thêm một đoạn hai lần, lỗi ứng dụng và nhật ký cho biết: java.lang.IllegalStateException: Phân đoạn đã được thêm vào: ... –

+0

Bạn nói đúng, không cần thiết phải giữ tham chiếu đến mMainLayout. Nhưng tôi phải giữ một số tham chiếu xem để cập nhật xem khi nhận dữ liệu từ máy chủ. –

+0

Ứng dụng của tôi không phải là sự cố, vì vậy tôi nghĩ rằng không có sự trợ giúp nào để gọi fragment.isAdded –

2

Bạn có thể thử với mã, tôi đã phải đối mặt với vấn đề tương tự đã được giải quyết với dưới đây thay đổi. Trong trường hợp đó, không cần phải thực hiện tất cả các tham chiếu trong số onDestroyView. như trong caseyou cần phải luôn luôn thực hiện kiểm tra null trước khi sử dụng các tài liệu tham khảo bất cứ nơi nào khác trong mã.

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

Khi mMainlayout không phải là null, nó có nghĩa là ví dụ mảnh của bạn đã có một ví dụ của mMainLayout và đã thêm vào ViewGroup container không cần phải thêm nó một lần nữa. Bạn đang gặp sự cố khi bạn đang thêm cùng một lượt xem vào cùng một vùng chứa.

+0

Tôi đã kết thúc câu hỏi cuối cùng trong câu hỏi của tôi rằng tôi đã giải quyết vấn đề giống như bạn. Tôi muốn biết rằng tại sao lượt xem/phân đoạn được thêm hai lần. –

+0

Khi bố cục giống nhau đã được thêm vào trong vùng chứa ViewGroup của bạn, vì vậy chúng tôi cần thực hiện kiểm tra null để không thêm nó hai lần. – Swapnil

Các vấn đề liên quan