web-dev-qa-db-ger.com

ViewPager.setOffscreenPageLimit (0) funktioniert nicht wie erwartet

Die Fragmente, die ich in meiner ViewPager-Instanz verwende, sind ziemlich ressourcenintensiv. Daher möchte ich nur jeweils eines laden. Wenn ich folgendes probiere:

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

Meine FragmentStatePagerAdapter.getItem(int position)-Override-Funktion wird dreimal aufgerufen. Dies ist der Fall, wenn ich mViewPager.setOffscreenPageLimit(1) anrufe. Ich würde erwarten, dass es nur einmal aufgerufen wird, da ich 0 Offscreen-Seiten angegeben habe. 

Ich glaube, ich rufe alles richtig an, denn wenn ich mViewPager.setOffscreenPageLimit(2) anrufe, wird FragmentStatePagerAdapter.getItem(int position) fünfmal aufgerufen, wie ich es erwarten würde. 

Benötigt ViewPager mindestens 1 Offscreen-Seiten, oder mache ich hier etwas falsch? 

91
Chris Lacy

Benötigt ViewPager mindestens 1 Offscreen-Seiten

Ja. Wenn ich den Quellcode richtig lese, sollte in LogCat eine entsprechende Warnung angezeigt werden.

Requested offscreen page limit 0 too small; defaulting to 1
108
CommonsWare

Der beste Weg, den ich gefunden habe, war setUserVisibleHint
Fügen Sie dies Ihrem Fragment hinzu 

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

Zuerst hinzufügen 

   boolean isFragmentLoaded = false;

als

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

        isFragmentLoaded = true;
    }
else{
     }
}
7
user5308871

Sie können es wie folgt versuchen:

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

in meinem Fall wollte ich einige Animationen in Ansichten starten, aber mit setUserVisibleHint gab es einige Probleme ...
Meine Lösung lautet:

1/addOnPageChangeListener für Ihren Adapter:

mViewPager.addOnPageChangeListener(this);

2/OnPageChangeListener implementieren:

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3/überschreiben Sie die 3 Methoden:

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

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4/deklarieren und initialisieren Sie diese Variable in Ihrer Klasse

private static int mTabState = 1;

notice : Ich habe drei Fragmente in meinem Adapter und benutze mTabState für setCurrentItem und die aktuelle Position des Adapters, die erkennen, welches Fragment dem Benutzer rechtzeitig angezeigt wird ... 5/in der Methode onPageSelected fügen Sie diese Codes hinzu:

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

wenn die vorherige Seite oder die aktuelle Seite Seite 0 ist (Fragment in Position 0), dann machen Sie das 

6/Jetzt in Ihrer Fragment-Klasse (Fragment in Position 0 des Adapters) müssen Sie einen Broadcast-Empfänger erstellen und ihn in der Methode onResume registrieren und die Registrierung von onPause methos aufheben:

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

summary: Ich habe einen Fragment Pager Adapter mit drei Fragmenten. Ich möchte einige Animationen auf Ansichten in Fragment in Position 0 des Adapters zeigen. Dafür verwende ich BroadcastReceiver. Wenn Fragment ausgewählt ist, starte ich die Animationsmethode und zeige die Ansichten für Benutzer. Wenn Fragment für Benutzer nicht angezeigt wird, versuche ich, unsichtbare Ansichten anzuzeigen.

1
AREF

ViewPager lädt standardmäßig die nächste Seite (Fragment), die Sie mit setOffscreenPageLimit (0) nicht ändern können. Aber du kannst etwas tun, um zu hacken. Sie können die onPageSelected-Funktion in Activity implementieren, die den ViewPager enthält. Im nächsten Fragment (das Sie nicht laden möchten) schreiben Sie eine Funktion, beispielsweise showViewContent (), in die Sie den gesamten Ressourcen verbrauchenden Init-Code einfügen und vor der onResume () -Methode nichts tun. Rufen Sie dann die Funktion showViewContent () in onPageSelected auf. Hoffe das wird helfen.

dies mag ein alter Thread sein, aber das scheint für mich zu funktionieren. Überschreiben Sie diese Funktion:

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

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

glückliche codierungen ...

0
ralphgabb

Ich habe irgendwie das gleiche Problem. Ich habe auf dieser Site einen nützlichen Code gefunden und ihn transformiert.

Das min int für mViewPager.setOffscreenPageLimit (...); ist 1, selbst wenn Sie sie auf 0 ändern, werden noch 2 Seiten geladen.

Als Erstes müssen Sie ein statisches int erstellen. Wir rufen maxPageCount auf und überschreiben die FragmentStatePagerAdapter-Methode getCount (), um maxPageCount zurückzugeben:

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

Erstellen Sie dann eine statische Methode, auf die von jedem beliebigen Punkt im Programm aus zugegriffen werden kann, um diesen maxCount zu ändern:

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

Jetzt initialisieren Sie maxPageCount auf 1. Wenn Sie möchten, können Sie eine weitere Seite hinzufügen. In meinem Fall, als ich den Benutzer brauchte, um die aktuelle Seite zuerst zu behandeln, bevor er die andere erzeugte. Er macht es und kann dann problemlos zur nächsten Seite streichen. 

Ich hoffe es hilft jemandem.

0
K20

Benutze das // boolean zum Abrufen von Daten erstellen 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;
    }
} 
0
Rohit Sharma

bereiten Sie für die Funktion "instantiateItem" einfach das Fragment vor, aber laden Sie nicht den umfangreichen Inhalt.

Verwenden Sie "onPageChangeListener", damit Sie jedes Mal, wenn Sie eine bestimmte Seite aufrufen, den umfangreichen Inhalt laden und ihn anzeigen.

0

Bitte versuchen Sie diesen Code, um das Problem der Aktualisierung der Ansicht im Viewpager zu beheben.

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