2012-09-03 37 views
8

Tôi có một số ViewPager (mở rộng FragmentPagerAdapter) chứa hai số Fragments. Những gì tôi cần chỉ là làm mới ListView cho mỗi Fragment khi tôi vuốt giữa chúng. Đối với điều này tôi đã thực hiện giao diện ViewPager.OnPageChangeListener (cụ thể là onPageScrollStateChanged). Để giữ tham chiếu đến Fragment, tôi sử dụng HashTable. Tôi lưu trữ tài liệu tham khảo để Fragments trong HashTable trong getItem() phương pháp:FragmentPagerAdapter không tạo lại Fragments về thay đổi định hướng?

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

Vì vậy, khi tôi vuốt từ một Fragment khác các onPageScrollStateChanged gây nên nơi tôi sử dụng HashTable để gọi phương thức cần thiết trong cả Fragments (refresh):

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

Mọi thứ diễn ra tốt đẹp cho đến khi sự kiện orientation change xảy ra. Sau đó các mã trong refresh() phương pháp, đó là:

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

kết quả trong 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) 

Giả sử xem Content không được tạo ra thực sự tôi đặt biến boolean trong onActivityCreated() phương pháp để true và sử dụng if/else điều kiện để gọi getListView() hoặc không, hiển thị chế độ xem hoạt động và nội dung được tạo thành công.

Sau đó, tôi đã gỡ lỗi để xem khi nào FragmentPagerAdapter gọi getItem() và nó xảy ra phương thức không được gọi sau sự kiện orientation change. Vì vậy, có vẻ như nó ViewPager giữ tham chiếu đến cũ Fragments. Đây chỉ là giả định của tôi.

Vì vậy, có cách nào để thực thi ViewPager để gọi getItem() một lần nữa, vì vậy tôi có thể sử dụng tham chiếu thích hợp cho hiện tại Fragments? Có thể là một số giải pháp khác? Cảm ơn nhiều.

Trả lời

4

Sau đó, tôi đã gỡ lỗi để xem khi nào FragmentPagerAdapter gọi getItem() và nó xảy ra phương thức không được gọi sau sự kiện thay đổi hướng. Vì vậy, có vẻ như nó ViewPager giữ tài liệu tham khảo cho mảnh vỡ cũ.

Các đoạn sẽ được tự động tạo lại, giống như bất kỳ đoạn nào có thay đổi cấu hình. Ngoại lệ sẽ là nếu bạn đã sử dụng setRetainInstance(true), trong trường hợp này, chúng phải là các đối tượng phân đoạn giống như trước đây.

Vì vậy, có cách nào để thực thi ViewPager gọi hàm getItem() một lần nữa, vì vậy tôi có thể sử dụng tham chiếu thích hợp cho Phân đoạn hiện tại không?

Điều gì là sai với các đoạn có trong đó?

+0

Tôi không sử dụng 'setRetainInstance()' trong đó. Vấn đề là trong trường hợp ngoại lệ bật lên sau 'thay đổi định hướng'. Tôi chỉ giả sử các mảnh vỡ cũ đang được sử dụng, bởi vì tôi đã kiểm tra điều kiện 'onActivityCreated()' được thực hiện cho cả hai. – Eugene

+0

@siik: Khi nào bạn gọi phương thức 'refresh()' này? Và khi nào bạn rút ra những mảnh vỡ mới được tạo ra để điền vào (ick) 'Hashtable' của bạn? – CommonsWare

+0

Tôi đang gọi phương thức 'refresh()' này trong 'onPageScrollStateChanged()' (đang triển khai giao diện 'ViewPager.OnPageChangeListener', tức là khi tôi vuốt giữa' Fragments'). Và tôi cư 'HashTable' trong phương thức' getItem() 'của lớp mở rộng' FragmentPagerAdapter' – Eugene

0

Tôi đã dành vài ngày tìm kiếm một giải pháp cho vấn đề này, và nhiều điểm đã được tìm ra:

  • sử dụng FragmentPagerAdapter thay vì FragmentStatePagerAdapter

  • sử dụng FragmentStatePagerAdapter thay vì FragmentPagerAdapter

  • trả lại POSITION_NONE trên getItemPosition ghi đè FragmentPagerAdapter

  • không sử dụng FragmentPagerAdapter nếu bạn cần thay đổi năng động của Những mảnh vỡ

  • và nhiều nhiều nhiều người khác ...

Trong ứng dụng của tôi, giống như Eugene, tôi quản lý bản thân các trường hợp tạo mảnh vỡ. Tôi giữ nó trong một số HashMap<String,Fragment> bên trong một số lớp chuyên biệt, vì vậy các mảnh không bao giờ được phát hành, tăng tốc ứng dụng của tôi (nhưng tiêu thụ nhiều tài nguyên hơn).

Vấn đề là khi tôi xoay máy tính bảng (và điện thoại). Các getItem(int) không được gọi nữa cho mảnh đó, và tôi không thể thay đổi nó.

Tôi thực sự dành nhiều thời gian cho đến khi thực sự tìm thấy một giải pháp, vì vậy tôi cần phải chia sẻ nó với cộng đồng StackOverflow, người đã giúp tôi rất nhiều nhiều lần ...

Các giải pháp cho vấn đề này, mặc dù công việc khó khăn để tìm thấy nó, là khá đơn giản:

Chỉ cần giữ tham chiếu đến FragmentManager trong constructor của FragmentPagerAdapter mở rộng:

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

    } 
} 

Thats tất cả. Và nó sẽ hoạt động như một sự quyến rũ ...

+1

của nó không làm việc cho tôi getItem không bao giờ kêu gọi thay đổi định hướng. – JosephM

+0

this.mFragmentManager = context.getSupportFragmentManager(); – alijunior

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