2013-06-06 40 views
29

Tôi muốn thực hiện điều này: enter image description here
Tôi sử dụng một ViewPager với một FragmentStatePagerAdapter.
tôi bắt đầu với ví dụ từ trang này:
http://developer.android.com/reference/android/support/v4/app/FragmentStatePagerAdapter.htmlLàm thế nào để tiêu diệt các mảnh vỡ cũ trong FragmentStatePagerAdapter

Đây là bộ chuyển đổi ViewPager tôi:

public static class MyAdapter extends FragmentStatePagerAdapter { 
     public MyAdapter(FragmentManager fm) { 
      super(fm); 
     } 

     @Override 
     public int getCount() { 
      return NUM_ITEMS; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      return ArrayListFragment.newInstance(position); 
     } 

     @Override 
     public void destroyItem(ViewGroup container, int position, Object object) { 
      super.destroyItem(container, position, object); 
     } 
    } 

Mỗi trang của ViewPager tôi chứa một ListView với một số dữ liệu. Hiện tại khi tôi chuyển sang một trang mới trong ViewPager, nó sẽ tăng bộ nhớ RAM rất nhanh chóng.
Tôi nên xóa các đoạn cũ như thế nào?
Tôi cũng sử dụng điều này, nhưng nó không làm gì:

public void destroyItem(ViewGroup container, int position, Object object) { 

    FragmentManager manager = ((Fragment) object).getFragmentManager(); 
    FragmentTransaction trans = manager.beginTransaction(); 
    trans.remove((Fragment) object); 
    trans.commit(); 

    super.destroyItem(container, position, object); 
} 

Ngoài ra còn có một sự chậm trễ 1-2 giây sau khi tôi chuyển đổi một cách nhanh chóng đến một trang mới hoặc trang cũ. Có kỹ thuật nào để loại bỏ sự chậm trễ đó không. Nếu tôi chuyển sang một trang mới và chờ 2 giây thì chuyển đổi tiếp theo sẽ không còn chậm trễ nữa.

Thử nghiệm trên Nexus 7.

+0

Bạn có giải pháp nào cho vấn đề này không? –

+0

xin vui lòng cung cấp giải pháp của bạn @vovahost – jyomin

Trả lời

12

Bạn không nên cố gắng can thiệp vào cách Android quản lý việc triển khai Fragment của bạn.Giá trị mặc định cho setOffScreenPageLimit phải là một. Điều này có nghĩa là Android sẽ phá hủy các mảnh vỡ cũ khi bộ nhớ bị cạn. Miễn là bạn không có vấn đề về bộ nhớ, chỉ cần để nguyên.

Lý do khiến bộ nhớ của bạn tăng lên là do Android giữ Fragment trường hợp trong bộ nhớ để có thể kết nối lại với chúng thay vì phải khởi tạo chúng. Tôi khuyên bạn nên tài khoản cho các trường hợp của Fragment trường hợp của bạn bị phá hủy bởi hệ điều hành, tiết kiệm trạng thái của họ nếu điều đó xảy ra, và để cho hệ điều hành làm công việc của mình.

Độ trễ bạn đang gặp phải có thể do một số tính toán chuyên sâu trên luồng giao diện người dùng. Nếu có, tôi khuyên bạn nên chuyển nó ra, ví dụ: AsyncTask. Tuy nhiên, nếu không có mã, chỉ cần đoán xem điều gì có thể gây ra vấn đề. Nhưng chỉ có một sự chậm trễ ban đầu cho thấy rằng bạn đang tải một cái gì đó mà có thể chặn các chủ đề giao diện người dùng.

Cập nhật: Hãy nhìn vào https://stackoverflow.com/a/9646622/170781 trong đó vạch ra rất gọn gàng như thế nào ViewPager xử lý Fragment trường.

+1

ohhh justOffOffScreenPageLimite save me ... i có 4 tab fragment khi tôi di chuyển từ 1 đến 4 và 4 đến 1st nó xóa tất cả dữ liệu nhưng setOffscreenLimte khôi phục trạng thái đó Cảm ơn một lottttttttttttttt ... – CoronaPintu

+0

Bạn nói đúng. Đã xảy ra sự cố với tính toán trên chuỗi giao diện người dùng – vovahost

+0

Rất vui khi tôi có thể trợ giúp! – Eric

3

Các FragmentStatePagerAdapter đã rất thanh đạm với bộ nhớ vì nó phá hủy không cần thiết fragments của bạn tự động. Nó chỉ giữ các khung nhìn của các mảnh trực tiếp bên trái và bên phải của mục hiện đang được hiển thị và phá hủy các mục khác.

Ví dụ: Vì vậy, một khi bạn swipe để đi đúng hướng, nó nạp trước sớm để có phải hàng xóm-đoạn và phá hủy các mảnh vỡ mà bây giờ là hai khe trên bên trái của mảnh hiển thị hiện hành.

+1

Bộ nhớ dường như luôn luôn chồng chất lên, những gì bạn đang nói về mặt lý thuyết là đúng nhưng không xảy ra. –

+0

bạn đang tải 50mb-bitmaps với 33k-modem sau đó? :) Tôi chưa bao giờ thấy hành vi như vậy khi tôi sử dụng FSPA. – bofredo

+1

Tôi biết những gì im nói về không lo lắng, đây là một số tài liệu tham khảo mã mà tôi đăng bạn có thể thấy cho bản thân của bạn bộ nhớ chồng chất lên. http://stackoverflow.com/questions/18241433/fragments-are-not-being-released-from-memory –

1

Tôi nghĩ rằng vấn đề không phải với ViewPager là trên ListFragments. Bạn hiển thị loại nội dung nào trên chúng? Bạn có phân bổ nhiều hình ảnh không? Bạn có thể đăng mã của ListFragment của bạn?

Tôi muốn đưa ra nhận xét nhưng vì tôi không có đủ điểm tôi hy vọng sẽ trợ giúp bằng cách chỉnh sửa phản hồi này.

1

Chế độ xemPager có phương thức setOffscreenPageLimit cho phép bạn chỉ định số lượng trang được bộ điều hợp lưu giữ. Vì vậy, các mảnh của bạn ở xa sẽ bị phá hủy.

Thật khó để nói điều gì có thể là vấn đề cụ thể của bạn vì tôi không biết phân đoạn của bạn là gì. Bởi âm thanh của 1-2 giây chậm trễ có vẻ như bạn có thể làm một số công việc trên thread UI. Ngoài ra những gì khác bạn đang làm trong mảnh của bạn đó là bộ nhớ tiêu thụ? Có lẽ bạn đang tải hình ảnh vào một số bộ nhớ cache tĩnh và không giải phóng chúng khi loại bỏ đoạn? Bạn có thể vui lòng cung cấp mã phân đoạn của bạn, vì vậy tôi có thể xem nó đang làm gì?

Nói chung, tôi khuyên bạn nên bán một tệp HPROF cho ứng dụng của bạn ngay khi cần thêm bộ nhớ và phân tích các tham chiếu qua MAT (công cụ phân tích bộ nhớ). Bạn đang rõ ràng có vấn đề rò rỉ bộ nhớ và tôi rất nghi ngờ vấn đề là trong Fragments mình không bị phá hủy.

Trong trường hợp bạn không biết cách phân tích bộ nhớ heap, đây là một số video tốt. Tôi không thể đếm bao nhiêu lần nó đã giúp tôi xác định và thoát khỏi rò rỉ bộ nhớ trong các ứng dụng của tôi.

12

Tôi gặp sự cố tương tự. Nhưng trong trường hợp của tôi ViewPager là bên trong của một mảnh khác. và sau khi loại bỏ ViewPagerFragment khỏi FragmentManager, tất cả các mảnh từ FragmentStatePagerAdapter vẫn nằm trong trình quản lý phân mảnh. vì vậy sau vài thay đổi như vậy, nó là OutOfMemoryError. Sau đó, tôi bật nhật ký FragmentManager bằng cách:

FragmentManager.enableDebugLogging(true); 

Và nhận thấy rằng id của mỗi phân đoạn mới đều bị nhiễm mỡ mỗi lần. Nó chỉ xảy ra với StatePagerAdapter. Để giải quyết vấn đề này tôi gọi loại bỏ cho mỗi mảnh đã được instantinated.

protected void dispatchOnDetach(Iterable<Fragment> fragments) { 
    if (fragments == null) 
     return; 

    Activity aa = getActivity(); 
    if (aa == null) 
     return; 

    IBaseActivity ba = (IBaseActivity) aa; 
    if (ba.isActivityStopped()) 
     return; 

    FragmentManager frMan = ba.getSupportFragmentManager(); 
    FragmentTransaction frTr = frMan.beginTransaction(); 

    for (Fragment fr : fragments) { 
     if (fr != null) { 
      frTr.remove(fr); 
     } 
    } 

    frTr.remove(this); 
    frTr.commit(); 

} 

Trong trường hợp của bạn. nếu bạn không thay đổi ViewPager trong thời gian chạy thì có thể, bộ thu gom rác đó không thể phá hủy các mảnh của bạn ngay cả sau khi xóa khỏi trình quản lý phân mảnh vì một số tham chiếu đến chúng. Bạn nên kiểm tra xem một số lớp học toàn cầu có sử dụng chúng hay không.

Và vì mục đích tối ưu hóa, bạn có thể lưu vào bộ nhớ cache mọi đoạn được tạo bằng SoftReference hoặc LruCache. Ví dụ:

public class MyAdapter extends FragmentStatePagerAdapter { 

private final LruCache<Integer, Fragment> mCache; 

public MyAdapter(FragmentManager fm) { 
    super(fm); 
    mCache = new LruCache<Integer, Fragment>(10); 
} 

@Override 
public int getCount() { 
    return NUM_ITEMS; 
} 

@Override 
public Fragment getItem(int position) { 
    return mCache.get(position); 
} 

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    super.destroyItem(container, position, object); 
} 

private class MyCache extends LruCache<Integer, Fragment> { 

    public MyCache(int maxSize) { 
     super(maxSize); 
    } 

    @Override 
    protected Fragment create(Integer key) { 
     return ArrayListFragment.newInstance(key); 
    } 
} 
} 
+0

Trường hợp chính xác bạn gọi là loại bỏ trên phân đoạn instantiated, xin vui lòng? –

+0

Trong onDetachMethod. – akelix

1

Ghi đè điều này trong FragmentStatePagerAdapter, lưu ý thay đổi nhỏ.

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    if (position >= getCount()) { 
    FragmentManager manager = ((Fragment) object).getFragmentManager(); 
    FragmentTransaction trans = manager.beginTransaction(); 
    trans.remove((Fragment) object); 
    trans.commit(); 
} 
Các vấn đề liên quan