2011-08-02 87 views
9

Tôi đang thiết kế một ứng dụng cho phép người dùng lật giữa nhiều trang trong ViewPager. Tôi đã cố gắng tìm ra cách loại bỏ một thể hiện Fragment từ một trang khi nó không còn hiển thị trên màn hình, lưu nó vào (ví dụ, HashMap), và sau đó khôi phục nó để khi người dùng lật trở lại trang đó, các chế độ xem và mọi thứ khác trong đó sẽ ở trong cùng trạng thái trước khi xóa. Ví dụ: trang đầu tiên của tôi là màn hình đăng nhập giúp các thành phần bố cục nhất định trên trang cụ thể đó hiển thị/ẩn trên đăng nhập thành công. Khi tôi lật lại đủ trang rồi lật lại trang đầu tiên, bố cục được đặt lại. Điều này trở thành một vấn đề đối với một trang khác của tôi chứa một mạng lưới cuộn lớn, ngang/dọc của dữ liệu mà tôi sử dụng một chuỗi trong nền để vẽ khi nó khởi tạo. Tôi sử dụng hộp thoại tiến trình để thông báo cho người dùng về tiến độ tải và điều đó trở nên thực sự gây phiền nhiễu mỗi khi tôi phải tải nó.Android: Viewpager và FragmentStatePageAdapter

Vì vậy, tôi đã làm một số nghiên cứu ...

tôi duyệt qua các mã nguồn cho FragmentStatePageAdapter và trong destroyItem() gọi lại, trạng thái của dụ Fragment đang được gỡ bỏ sẽ được lưu vào một ArrayList. Khi một cá thể mới của Fragment được tạo trong callback instantiateItem(), nếu một cá thể của một mục chưa tồn tại (chúng theo dõi điều này bằng cách sử dụng một ArrayList), một cá thể Fragment mới được tạo và trạng thái đã lưu của nó được khởi tạo với dữ liệu Fragment.SavedState tương ứng. Thật không may, dữ liệu này không bao gồm trạng thái mà Views được mặc dù tôi nhận thấy rằng đối với các trang có GridView/ListView, trạng thái của Views được khôi phục bằng cách nào đó (nếu tôi cuộn đến một số vị trí ngẫu nhiên, lật một vài trang và quay lại , nó sẽ không được đặt lại).

Theo API:

Các trạng thái lưu trữ không thể chứa phụ thuộc vào những mảnh còn lại - đó là nó không thể sử dụng putFragment (Bundle, String, Fragment) để lưu trữ một tham chiếu đoạn vì tham chiếu đó có thể không hợp lệ khi trạng thái đã lưu này được sử dụng sau này . Tương tự như vậy, mục tiêu của Fragment và kết quả là mã không được bao gồm trong trạng thái này.

Là một noob cho Android, tôi không hoàn toàn chắc chắn rằng tôi hiểu câu cuối cùng.

Điều đó đang được nói, có cách nào để lưu vào bộ nhớ cache Xem trạng thái không? Nếu không, tôi nghĩ tôi sẽ tiếp tục và bỏ đi tất cả các trang mảnh trong bộ nhớ.

Trả lời

1

Nhìn vào các tài liệu khác nhau, phỏng đoán tốt nhất của tôi là các chế độ xem bạn đang tạo không có ID được đính kèm với chúng. Giả sử rằng trạng thái đã lưu của phân đoạn được tạo ra từ Fragment.onSaveInstanceState, thì đoạn sẽ tự động lưu trạng thái của bất kỳ chế độ xem nào có id. Bạn có thể có một id mặc định liên kết với ListView của bạn/GridView nếu bạn tạo chúng từ một tệp bố trí. Bạn cũng có thể liên kết một id với các khung nhìn bằng cách gọi setId.

Ngoài ra, đối với đoạn tùy chỉnh đã điền của bạn, bạn cũng có thể phải làm điều gì đó tùy chỉnh trong onSaveInstanceState.

4

tôi đã cùng một vấn đề vấn đề và giải quyết nó bằng cách thực hiện hai chức năng

public void onSaveInstanceState (Bundle outState) 
    public void onActivityCreated (Bundle savedInstanceState) 

trên các mảnh vỡ mà tôi muốn lưu. Về chức năng đầu tiên, bạn nên lưu trong gói ngày mà bạn cần khôi phục các khung nhìn (trong trường hợp của tôi, tôi đã có một nhóm spinner vì vậy tôi đã sử dụng một mảng int để lưu vị trí của chúng).Hàm thứ hai, được gọi khi khôi phục phân đoạn của bạn, là nơi bạn triển khai quá trình khôi phục.

Tôi hy vọng điều này sẽ hữu ích. Tôi cũng làm cho bộ điều hợp của tôi kế thừa từ FragmentStatePageAdapter nhưng tôi không chắc chắn rằng điều này là bắt buộc.

+3

Bạn cần phải kế thừa từ FragmentStatePagerAdapter, nếu bạn chỉ sử dụng FragmentPagerAdapter sau đó onSaveInstanceState sẽ không được gọi. – Scott

2

Danh bạ nhà main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <TextView android:text="Page 1" android:id="@+id/textViewHeader" 
     android:layout_width="fill_parent" android:layout_height="wrap_content" 
     android:gravity="center" android:padding="10dip" android:textStyle="bold"></TextView> 
    <android.support.v4.view.ViewPager 
     android:layout_width="fill_parent" android:layout_height="fill_parent" 
     android:id="@+id/viewPager" /> 
</LinearLayout> 

Thiết lập ViewPager

ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager); 
MyPagerAdapter adapter = new MyPagerAdapter(this); 
viewPager.setAdapter(adapter); 

Các PagerAdapter

@Override 
public void destroyItem(View view, int arg1, Object object) { 
     ((ViewPager) view).removeView((View)object); 
} 
@Override 
public int getCount() { 
      return views.size(); 
} 
@Override 
public Object instantiateItem(View view, int position) { 
      View view = views.get(position); 
      ((ViewPager) view).addView(view); 
      return view; 
} 
@Override 
public boolean isViewFromObject(View view, Object object) { 
      return view == object; 
} 

trông vào đây để biết thêm chi tiết view pager example

1

H Đây là một ví dụ về cách tôi thực hiện bộ nhớ đệm trong PagerAdapter. Sau khi điền vào bộ nhớ cache, tất cả các yêu cầu xem trong tương lai được phục vụ từ bộ nhớ cache, chỉ dữ liệu được thay thế.

public class TestPageAdapter extends PagerAdapter{ 

private int MAX_SIZE = 3; 
private ArrayList<SoftReference<View>> pageCache = new ArrayList<SoftReference<View>>(3); 


public TestPageAdapter(Context context){ 
    // do some initialization 
} 

@Override 
public int getCount() { 
    // number of pages 
} 

private void addToCache(View view){ 
    if (pageCache.size() < MAX_SIZE){ 
     pageCache.add(new SoftReference<View>(view)); 
    } else { 
     for(int n = (pageCache.size()-1); n >= 0; n--) { 
      SoftReference<View> cachedView = pageCache.get(n); 
      if (cachedView.get() == null){ 
       pageCache.set(n, new SoftReference<View>(view)); 
       return; 
      } 
     } 
    } 
} 

private View fetchFromCache(){ 
    for(int n = (pageCache.size()-1); n>= 0; n--) { 
     SoftReference<View> reference = pageCache.remove(n); 
     View view = reference.get(); 
     if (view != null) { 
      return view; 
     } 
    } 
    return null; 
} 

@Override 
public Object instantiateItem(View collection, int position) { 
    View view = fetchFromCache(); 
    if (view == null) { 
     // not in cache, inflate manually 
     LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     view = inflater.inflate(R.layout.page, null); 
    } 
    setData(view, position); 
    ((ViewPager) collection).addView(view, 0); 
    return view;   
} 

private void setData(View view, int position){ 
    // set page data (images, text ....) 
} 

public void setPrimaryItem(ViewGroup container, int position, Object object) { 
    currentItem = (View)object; 
} 

public View getCurrentItem() { 
    return currentItem; 
} 

@Override 
public boolean isViewFromObject(View view, Object object) { 
    return view == ((View) object); 
} 

@Override 
public void destroyItem(View collection, int arg1, Object view) { 
    ((ViewPager) collection).removeView((View) view); 
    addToCache((View) view); 
} 

} 
0

Tôi cũng chạy vào vấn đề này khi tôi đã sử dụng PagerSlidingTabStrip và sử dụng và thể hiện của FragmentPagerAdapter, chuyển sang FragmentStatePagerAdapter chắc chắn làm việc.

Sau đó, tôi sử dụng onSaveInstanceState() để lưu sate

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