ViewPager.setOffscreenPageLimit(0)が期待どおりに機能しない


100

ViewPagerインスタンスで使用するフラグメントはかなりのリソースを消費するため、一度に1つだけロードしたいと思います。私が次のことを試みると:

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

私のFragmentStatePagerAdapter.getItem(int position)オーバーライド関数は3回呼び出されますmViewPager.setOffscreenPageLimit(1)。これは、を呼び出したときに発生します。オフスクリーンページを0に指定したので、1回だけ呼び出されると思います。

私は、私が呼び出した場合ので、私は、すべてを正しく呼んでいると信じてmViewPager.setOffscreenPageLimit(2)FragmentStatePagerAdapter.getItem(int position)私が期待するように5回と呼ばれています。

ViewPagerには少なくとも1つのオフスクリーンページが必要ですか、それともここで何か問題がありますか?


9
機能リクエストを追加しました:code.google.com/p/android/issues/detail?id
Mark


タブは3つしかなく、設定ViewPager.setOffscreenPageLimit(2)はうまくいきました。試してみるViewPager.setOffscreenPageLimit(totTabs - 1)
シビン

回答:


112

ViewPagerには少なくとも1つのオフスクリーンページが必要ですか?

はい。ソースコードを正しく読んでいる場合、LogCatで次のような警告が表示されます。

Requested offscreen page limit 0 too small; defaulting to 1

6
これは解決策ではありません!2つではなく1つのフラグメントのみをロードしたいのですが、これはどういうわけか可能ですか?
HGPB 2013

14
@ハラルド:「確かにこれはどういうわけか可能ですか?」-ではありませんViewPagerViewPagerビューが存在するようにこれらのフラグメントを作成し、ユーザーがそれらの間をスワイプできるようにします。アニメーション効果により、古いビューが画面からスライドし、新しいビューが画面にスライドします。ViewPager存在しないものの間をスワイプできる独自のものを作成してみてください。詳細については、code.google.com
p /

2
はい、この問題を読みました。ただ論理的ではありません。私はsetOffscreenPageLimit(0)0 にできると期待しています。それから私はその結果に自分で対処することができます。たとえば、デフォルトの空のフラグメントは、フラグメントが読み込まれるまでプレースホルダーになります。これらはすべて、UIスレッドから実行できます。とにかく、あまり考えていません。
HGPB 2013

5
@Haraldo:「たとえば、フラグメントが読み込まれるまで、デフォルトの空のフラグメントがプレースホルダーである可能性があります」-現在のフラグメントにプレースホルダーがあってViewPagerもかまいません。 。
CommonsWare 2013

2
onPageChangeListenerが解決策のようです。
alicanbatur 2013

123

私が見つけた最良の方法はsetUserVisibleHintで
、これをフラグメントに追加しました

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

1
+++++このソリューション!!! おかげで、このコードを追加した後、初めてNPLを取得しました。trycatchブロックを追加しただけで、その動作は完璧です!!!
Bhavin Chauhan 2015

1
これを使用すると、secondViewPager Fragmentに日付が読み込まれず、2番目のフラグメントで3番目のフラグメントの読み込みデータが読み込まれます。誰かが私を助けてくれますか?
Arshad 2016

私は何かが欠けアム、setUserVisibleHintはonCreateView前に呼び出さ
アントンMakov

最高のソリューションは廃止されました
M.Sameer

@ M.Sameer setUserVisibleHintの代替手段は廃止されましたか?
ユディカルマ

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の前に呼び出されます
Zar E Ahmer

2

ViewPagerはデフォルトで、setOffscreenPageLimit(0)で変更できない次のページ(フラグメント)をロードします。しかし、あなたは何かをハックすることができます。onPageSelected関数は、ViewPagerを含むアクティビティに実装できます。次の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.
         */
    } 
}

ハッピーコーディング...


ウェブビューでどうですか?そのための新しいスレッドを作成することをお勧めします。
ラルフガブ2015

1

私の場合、ビューでいくつかのアニメーションを開始したかったのですが、setUserVisibleHintでいくつかの問題が発生しました...
私の解決策は次のとおりです:

1 /アダプタのaddOnPageChangeListener:

mViewPager.addOnPageChangeListener(this);

2 / OnPageChangeListenerを実装します。

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3/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;

注意:私はアダプターに3つのフラグメントがあり、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のフラグメント)で、ブロードキャストレシーバーを作成してonResumeメソッドに登録し、onPauseメソッドで登録解除する必要があります。

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

概要:フラグメントページャーアダプターの魔女が3つのフラグメントを表示しています。アダプターの位置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(...);の最小整数。は1なので、0に変更しても、2ページが読み込まれます。

まず最初に、静的なintを作成し、maxPageCountを呼び出し、FragmentStatePagerAdapterメソッドgetCount()をオーバーライドしてmaxPageCountを返します。

    @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

これを使用して//データをフェッチするためのブール値を作成します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.