ViewPager.setOffscreenPageLimit (0) không hoạt động như mong đợi


100

Các đoạn tôi sử dụng trong ViewPagertrường hợp của mình khá tốn tài nguyên, vì vậy tôi chỉ muốn tải từng đoạn một. Khi tôi thử những điều sau:

mViewPager.setOffscreenPageLimit(0);
mViewPager.setAdapter(mPagerAdapter);

FragmentStatePagerAdapter.getItem(int position)Chức năng ghi đè của tôi được gọi 3 lần, đó là những gì xảy ra khi tôi gọi mViewPager.setOffscreenPageLimit(1). Tôi mong rằng nó chỉ được gọi một lần, vì tôi đã chỉ định 0 trang ngoài màn hình.

Tôi tin rằng tôi đang gọi mọi thứ một cách chính xác, bởi vì nếu tôi gọi mViewPager.setOffscreenPageLimit(2), FragmentStatePagerAdapter.getItem(int position)sẽ được gọi 5 lần như tôi mong đợi.

ViewPager có yêu cầu tối thiểu 1 trang ngoài màn hình không hay tôi đang làm gì đó sai ở đây?


9
Tôi đã thêm một yêu cầu tính năng: code.google.com/p/android/issues/detail?id=56667
Đánh dấu


Tôi chỉ có 3 tab và cài đặt ViewPager.setOffscreenPageLimit(2)phù hợp với tôi. Hãy thửViewPager.setOffscreenPageLimit(totTabs - 1)
sibin

Câu trả lời:


112

ViewPager có yêu cầu tối thiểu 1 trang ngoài màn hình không

Đúng. Nếu tôi đang đọc đúng mã nguồn, bạn sẽ nhận được cảnh báo về điều này trong LogCat, đại loại như:

Requested offscreen page limit 0 too small; defaulting to 1

6
Đây không phải là một giải pháp! Tôi muốn chỉ tải 1 phân mảnh không phải 2. Chắc chắn điều này là có thể bằng cách nào đó?
HGPB

14
@Haraldo: "Chắc chắn điều này là có thể bằng cách nào đó?" - không với ViewPager. ViewPagertạo các mảnh này để các chế độ xem tồn tại, vì vậy người dùng có thể vuốt giữa chúng, với hiệu ứng động hiển thị chế độ xem cũ trượt khỏi màn hình và chế độ xem mới trượt lên màn hình. Bạn có thể thử viết của riêng mình ViewPagerđể có thể vuốt giữa những thứ không tồn tại. Bạn có thể đọc thêm về điều này tại code.google.com/p/android/issues/detail?id=56667#c3
CommonsWare vào

2
Có, tôi đã đọc vấn đề này. Chỉ là không hợp lý. Tôi kỳ vọng có thể bằng setOffscreenPageLimit(0)0. Sau đó tôi có thể tự giải quyết hậu quả. Một phân đoạn trống mặc định có thể là một trình giữ chỗ chẳng hạn cho đến khi các phân đoạn đó được tải. Tất cả đều có thể diễn ra ngoài chuỗi giao diện người dùng. Dù sao thì tôi cũng chưa nghĩ về nó nhiều.
HGPB

5
@Haraldo: "Một phân đoạn trống mặc định có thể là một trình giữ chỗ chẳng hạn cho đến khi các phân đoạn đó được tải" - bạn có thể có một trình giữ chỗ trong phân đoạn của mình ngay hôm nay, với việc triển khai hiện có, một trình giữ chỗ ViewPagermà bạn thay thế bằng nội dung thực khi có sẵn .
CommonsWare

2
onPageChangeListener dường như là giải pháp.
alicanbatur

123

Cách tốt nhất mà tôi tìm thấy là setUserVnableHint
thêm cái này vào phân đoạn của bạn

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here
    }else{
       // fragment is no longer visible
    }
}

1
+++++ cho giải pháp này !!! cảm ơn, sau khi thêm mã này, tôi đã nhận được NPL lần đầu tiên, tôi vừa thêm thử khối bắt và nó hoạt động hoàn hảo cho tôi !!!
Bhavin Chauhan

1
Khi sử dụng điều này, nó không tải ngày trên Phân đoạnViewPager thứ hai, trên phân đoạn thứ hai tải dữ liệu của phân đoạn thứ ba. Ai đó có thể giúp tôi không?
Arshad

Tôi có thiếu cái gì, setUserVisibleHint gọi trước khi onCreateView
Anton Makov

Giải pháp tốt nhất hiện đang bị phản đối
M.Sameer

@ M.Sameer có thay thế nào cho setUserVbrokenHint có deprectate không?
Yudi karma

8

Bạn có thể thử như thế này:

public abstract class LazyFragment extends Fragment {
    protected boolean isVisible;
    /**
     * 在这里实现Fragment数据的缓加载.
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }
    protected void onVisible(){
        lazyLoad();
    }
    protected abstract void lazyLoad();
    protected void onInvisible(){}

protected abstract void lazyLoad();
protected void onInvisible(){}

đó là câu trả lời tốt nhất!
Radesh

7

Thêm đầu tiên

   boolean isFragmentLoaded = false;

hơn

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && !isFragmentLoaded) {
        //Load Your Data Here like.... new GetContacts().execute();

        isFragmentLoaded = true;
    }
else{
     }
}

6
nhưng phương pháp này đòi hỏi trước onCreateView
Zar E Ahmer

2

ViewPager được mặc định tải trang tiếp theo (Fragment) mà bạn không thể thay đổi bằng setOffscreenPageLimit (0). Nhưng bạn có thể làm gì đó để hack. Bạn có thể triển khai chức năng onPageSelected trong Activity chứa ViewPager. Trong Fragment tiếp theo (mà bạn không muốn tải), bạn viết một hàm giả sử showViewContent () nơi bạn đặt tất cả mã init tiêu thụ tài nguyên và không làm gì trước phương thức onResume (). Sau đó gọi hàm showViewContent () bên trong onPageSelected. Hy vọng điều này sẽ giúp ích.


1

đây có thể là chủ đề cũ nhưng điều này dường như làm việc cho tôi. Ghi đè chức năng này:

@Override
public void setMenuVisibility(boolean menuVisible) { 
    super.setMenuVisibility(menuVisible);

    if ( menuVisible ) {
        /**
         * Load your stuffs here.
         */
    } else  { 
        /**
         * Fragment not currently Visible.
         */
    } 
}

mã hạnh phúc ...


có gì trên webview? Tôi khuyên bạn nên tạo một chủ đề mới cho điều đó.
ralphgabb

1

trong trường hợp của tôi, tôi muốn bắt đầu một số hoạt ảnh trong các chế độ xem, nhưng với setUserVbrokenHint có một số vấn đề ...
giải pháp của tôi là:

1 / addOnPageChangeListener cho bộ điều hợp của bạn:

mViewPager.addOnPageChangeListener(this);

2 / triển khai OnPageChangeListener:

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3 / ghi đè 3 phương thức:

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4 / khai báo và khởi tạo biến này trên lớp của bạn

private static int mTabState = 1;

lưu ý : tôi có ba đoạn trong bộ điều hợp của mình và sử dụng mTabState cho setCurrentItem và vị trí hiện tại của bộ điều hợp nhận ra đoạn nào được hiển thị cho người dùng kịp thời ... 5 / trong phương pháp onPageSelected, hãy thêm mã này:

if (mTabState == 0 || position == 0)
    {
        Intent intent = new Intent("animation");
        intent.putExtra("current_position", position);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

nếu trang trước hoặc trang hiện tại là trang 0 (phân đoạn ở vị trí 0) thì hãy thực hiện công cụ này

6 / bây giờ trong lớp phân mảnh của bạn (phân mảnh ở vị trí 0 của bộ điều hợp), bạn phải tạo bộ thu phát sóng và đăng ký nó trong phương thức onResume và hủy đăng ký nó trên Pause methos:

BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (Objects.equals(intent.getAction(), "animation"))
        {
            int currentPosition = intent.getIntExtra("current_position", 0);
            if (currentPosition == 0)
            {
                startAnimation();
                setViewsVisible();
            } else
            {
                setViewsInvisible();
            }
        }
    }
};

@Override
public void onResume()
{
    super.onResume();
    LocalBroadcastManager.getInstance(mContext).registerReceiver(broadcastReceiver, new IntentFilter("animation"));
}

@Override
public void onPause()
{
    super.onPause();
    LocalBroadcastManager.getInstance(mContext).unregisterReceiver(broadcastReceiver);
}

tóm tắt: tôi có phù thủy Fragment Pager Adapter hiển thị Ba Fragment trong đó, tôi muốn hiển thị một số Animations trên Views trong Fragment ở Vị trí 0 của Adapter, Đối với điều này, tôi sử dụng BroadcastReceiver. Khi Fragment được chọn, tôi bắt đầu phương thức Animation và hiển thị các View cho Người dùng, Khi Fragment không hiển thị cho người dùng, tôi cố gắng Invisible Views ...


1

Vui lòng dùng thử mã này để giải quyết vấn đề làm mới chế độ xem trong Viewpager ....

/* DO NOT FORGET! The ViewPager requires at least “1” minimum OffscreenPageLimit */
int limit = (mAdapter.getCount() > 1 ? mAdapter.getCount() - 1 : 1);
mViewPager.setOffscreenPageLimit(limit);

0

đối với chức năng "InstantiateItem", chỉ cần chuẩn bị phân đoạn, nhưng không tải nội dung nặng.

Sử dụng "onPageChangeListener" để mỗi khi bạn truy cập vào một trang cụ thể, bạn sẽ tải nội dung nặng của trang đó và hiển thị nó.


0

Tôi cũng có cùng một vấn đề. Tôi đã tìm thấy một số mã hữu ích trên trang web này và chuyển đổi nó.

Int tối thiểu cho mViewPager.setOffscreenPageLimit (...); là 1, vì vậy ngay cả khi bạn thay đổi nó thành 0, bạn vẫn sẽ tải được 2 trang.

Điều đầu tiên cần làm là tạo một int tĩnh, chúng ta sẽ gọi maxPageCount và ghi đè phương thức FragmentStatePagerAdapter getCount () để trả về maxPageCount:

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

Sau đó, tạo một phương thức tĩnh có thể truy cập từ bất kỳ vị trí nào trong chương trình sẽ cho phép bạn thay đổi Số tiền tối đa này:

public static void addPage(){
    maxPageCount++; //or maxPageCount = fragmentPosition+2
    mFragmentStatePagerAdapter.notifyDataSetChanged(); //notifyDataSetChanged is important here.
}

Bây giờ hãy khởi tạo maxPageCount thành 1. Khi nào bạn muốn, bạn có thể thêm một trang khác. Trong trường hợp của tôi, khi tôi cần người dùng xử lý trang hiện tại trước khi tạo trang khác. Anh ấy làm điều đó và sau đó, không có vấn đề gì có thể vuốt sang trang tiếp theo.

Hy vọng nó sẽ giúp một ai đó.


0

Sử dụng This // tạo boolean để tìm nạp dữ liệu private boolean isViewShown = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
} 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.