ViewPager.setOffscreenPageLimit (0)이 예상대로 작동하지 않습니다.


100

ViewPager인스턴스 에서 사용하는 조각 은 리소스 집약적이므로 한 번에 하나씩 만로드하고 싶습니다. 다음을 시도 할 때 :

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

FragmentStatePagerAdapter.getItem(int position)오버라이드 함수는 3 번 호출되는데, mViewPager.setOffscreenPageLimit(1). 오프 스크린 페이지를 0 개로 지정했기 때문에 한 번만 호출 될 것으로 예상합니다.

내가 호출하는 경우 때문에 내가 제대로 모든 전화 했어 생각 mViewPager.setOffscreenPageLimit(2), FragmentStatePagerAdapter.getItem(int position)내가 기대로 5 번이라고합니다.

ViewPager에 최소 1 개의 오프 스크린 페이지가 필요합니까, 아니면 여기서 뭔가 잘못하고 있습니까?


9
기능 요청을 추가했습니다. code.google.com/p/android/issues/detail?id=56667
Mark


3 개의 탭만 있고 설정이 ViewPager.setOffscreenPageLimit(2)효과적이었습니다. 시도ViewPager.setOffscreenPageLimit(totTabs - 1)
sibin

답변:


112

ViewPager에 최소 1 개의 오프 스크린 페이지가 필요합니까?

예. 소스 코드를 올바르게 읽고 있다면 LogCat에 다음과 같은 경고가 표시됩니다.

Requested offscreen page limit 0 too small; defaulting to 1

6
이것은 해결책이 아닙니다! 2가 아닌 1 개의 조각 만로드하고 싶습니다. 확실히 이것이 가능합니까?
HGPB 2013

14
@Haraldo : "확실히 이것은 어떻게 든 가능합니까?" - ViewPager. ViewPager이러한 조각을 생성하여 뷰가 존재하도록 사용자가 뷰 사이를 스 와이프 할 수 있습니다. 애니메이션 효과는 이전 뷰가 화면에서 미끄러지고 새 뷰가 화면으로 미끄러지는 것을 보여줍니다. ViewPager존재하지 않는 것들 사이를 스 와이프 할 수있는 자신 만의 글을 작성하는 것을 환영 합니다. 이에 대한 자세한 내용은 code.google.com/p/android/issues/detail?id=56667#c3
CommonsWare 2013

2
예,이 호를 읽었습니다. 논리적이지 않습니다. setOffscreenPageLimit(0)0 이 될 것으로 기대 합니다. 그러면 결과를 직접 처리 할 수 ​​있습니다. 예를 들어 기본 빈 조각은 조각이로드 될 때까지 자리 표시자가 될 수 있습니다. 이 모든 것이 UI 스레드에서 발생할 수 있습니다. 어쨌든 나는 그것에 대해 많이 생각하지 않았습니다.
HGPB 2013

5
@Haraldo : "기본 빈 프래그먼트는 예를 들어 프래그먼트가로드 될 때까지 자리 표시자가 될 수 있습니다."-현재 프래그먼트에 자리 표시자를 가질 수 있습니다. 기존 구현에서는 ViewPager사용 가능한 경우 실제 콘텐츠로 대체 할 수 있습니다. .
CommonsWare

2
onPageChangeListener가 해결책처럼 보입니다.
alicanbatur

123

내가 찾은 가장 좋은 방법은 setUserVisibleHint가
이것을 조각에 추가하는 것입니다.

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

1
이 솔루션을위한 +++++ !!! 감사합니다,이 코드를 추가 한 후 처음으로 NPL을 얻었습니다. 방금 try catch 블록을 추가했으며 그 작업은 저에게 완벽합니다 !!!
Bhavin Chauhan 2015-08-26

1
이것을 사용하면 secondViewPager 조각에 날짜를로드하지 않고 두 번째 조각에서는 세 번째 조각의로드 데이터를로드합니다. 누군가 나를 도울 수 있습니까?
Arshad

내가 뭔가를 놓친 거지, setUserVisibleHint는 onCreateView 전에 호출
안톤 Makov

이제 최상의 솔루션이 더 이상 사용되지 않습니다
M.Sameer 19

@ M.Sameer setUserVisibleHint에 대한 대안이 더 이상 사용되지 않습니까?
Yudi karma

8

다음과 같이 시도 할 수 있습니다.

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(){}

그 최고의 대답!
Radesh

7

먼저 추가

   boolean isFragmentLoaded = false;

...보다

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

        isFragmentLoaded = true;
    }
else{
     }
}

6
그러나이 방법은 onCreateView 전에 호출
AndroidGeek

2

ViewPager는 setOffscreenPageLimit (0)으로 변경할 수없는 다음 페이지 (Fragment)를로드하는 기본입니다. 하지만 해킹 할 수 있습니다. ViewPager를 포함하는 Activity에서 onPageSelected 함수를 구현할 수 있습니다. 다음 Fragment (로드하고 싶지 않음)에서 모든 리소스 소비 초기화 코드를 입력하고 onResume () 메서드 전에 아무것도하지 않는 showViewContent () 함수를 작성합니다. 그런 다음 onPageSelected 내에서 showViewContent () 함수를 호출합니다. 이것이 도움이되기를 바랍니다.


1

이것은 오래된 스레드 일 수 있지만 이것은 나를 위해 작동하는 것 같습니다. 이 기능을 재정의하십시오.

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

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

행복한 코딩 ...


webview에 뭐가 있어요? 이를 위해 새 스레드를 만드는 것이 좋습니다.
ralphgabb

1

제 경우에는 뷰에서 일부 애니메이션을 시작하고 싶었지만 setUserVisibleHint를 사용하면 몇 가지 문제가 있습니다 ...
제 솔루션은 다음과 같습니다.

1 / 어댑터에 대한 addOnPageChangeListener :

mViewPager.addOnPageChangeListener(this);

2 / OnPageChangeListener 구현 :

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3 / 세 가지 방법을 재정의하십시오.

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

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4 / 클래스에서이 변수를 선언하고 초기화합니다.

private static int mTabState = 1;

주의 사항 : 내 어댑터에 세 개의 조각이 있으며 setCurrentItem에 대해 mTabState를 사용하고 시간 내에 사용자에게 표시되는 조각을 인식하는 어댑터의 현재 위치를 사용합니다 ... 5 / onPageSelected 메서드에서 다음 코드를 추가합니다.

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

이전 페이지 또는 현재 페이지가 페이지 0 (위치 0의 조각)이면이 작업을 수행합니다.

6 / 이제 조각 클래스 (어댑터의 위치 0에있는 조각)에서 broadcast receiver를 만들고 onResume 메서드에 등록하고 onPause 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);
}

요약 : 나는 조각 호출기 어댑터 마녀가 그것에 세 조각을 보여줍니다, 나는 어댑터의 위치 0에 조각의 뷰에 일부 애니메이션을 표시하고 싶습니다.이를 위해 BroadcastReceiver를 사용합니다. 조각이 선택되면 애니메이션 메서드를 시작하고 사용자에게보기를 표시합니다. 조각이 사용자에게 표시되지 않으면 보이지 않는보기를 시도합니다 ...


1

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

"instantiateItem"함수의 경우 조각을 준비하고 무거운 콘텐츠를로드하지 마십시오.

"onPageChangeListener"를 사용하면 특정 페이지로 이동할 때마다 무거운 콘텐츠를로드하여 표시 할 수 있습니다.


0

나도 같은 문제가 있습니다. 이 사이트에서 유용한 코드를 찾아서 변환했습니다.

mViewPager.setOffscreenPageLimit (...);의 min int 1이므로 0으로 변경하더라도 2 페이지가로드됩니다.

가장 먼저 할 일은 maxPageCount를 호출하고 maxPageCount를 반환하도록 FragmentStatePagerAdapter 메서드 getCount ()를 재정의 할 정적 int를 만드는 것입니다.

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

그런 다음이 maxCount를 변경할 수있는 프로그램의 모든 위치에서 액세스 할 수있는 정적 메서드를 만듭니다.

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

이제 maxPageCount를 1로 초기화합니다. 원할 때마다 다른 페이지를 추가 할 수 있습니다. 내 경우에는 사용자가 다른 페이지를 생성하기 전에 먼저 현재 페이지를 처리해야 할 때. 그러면 문제없이 다음 페이지로 스 와이프 할 수 있습니다.

누군가를 돕기를 바랍니다.


0

Use This // 데이터를 가져 오기위한 부울 생성 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;
    }
} 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.