it-swarm.com.de

Zeigen Sie den Fragment Viewpager innerhalb eines Fragments an

Ich habe ein Fragment, das einen ViewPager enthält. Der ViewPager ist einem Adapter zugeordnet, der einen Satz Fragmente enthält.

Beim Laden des übergeordneten Fragments wird eine IllegalStateException mit der Nachricht angezeigt: Java.lang.IllegalStateException: Recursive entry to executePendingTransactions.

Einige Nachforschungen haben mich zu der Schlussfolgerung geführt, dass das System keine Fragmente innerhalb eines anderen Fragments anzeigen kann. Es gibt jedoch Anzeichen dafür, dass es möglich ist, genau dies mit der Verwendung eines ViewPagers zu tun ( Ein Fehler in ViewPager, der ihn verwendet anderes Fragment ).

Wenn ich meinem übergeordneten Fragment eine Schaltfläche hinzufüge, die auf meinem ViewPager mPager.setAdapter(mAdapter) aufruft, wird der ViewPager erfolgreich geladen. Das ist nicht ideal.

Das Problem muss sich dann auf den Fragment-Lebenszyklus beziehen. Meine Frage lautet daher: Hat jemand anderes einen Ausweg gefunden, und wenn ja, wie?

Gibt es eine Möglichkeit, die Einstellungen des Adapters auf dem ViewPager bis nach der Fragmenttransaktion zu verzögern?

Hier ist mein Parent-Fragment-Code:

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    final Button button = (Button)mView.findViewById(R.id.load_viewpager_button);
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mViewPager.setAdapter(mAdapter);
            button.setVisibility(View.GONE);
        }
    });

    mAdapter = new ViewPagerAdapter(getFragmentManager());
 //     mViewPager.setAdapter(mAdapter);

    return mView;
}

Und der Adapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        Bundle b = createBundle(position, mCursor);
        return TeamCardFragment.newInstance(b);
    }
}
54
howettl

verwenden Sie AsyncTask, um den Adapter für viewPager festzulegen. Für mich geht das. Die asyncTask dient dazu, das Originalfragment zu vervollständigen. und dann fahren wir mit viewPager-Fragmenten fort, um Rekursion zu vermeiden.

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    final Button button = (Button)mView.findViewById(R.id.load_viewpager_button);
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mViewPager.setAdapter(mAdapter);
            button.setVisibility(View.GONE);
        }
    });

    mAdapter = new ViewPagerAdapter(getFragmentManager());
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void,Void,Void>{
      protected Void doInBackground(Void... params) {
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
                   mViewPager.setAdapter(mAdapter);
        }
}
60
Yashwanth Kumar

Jords, ich denke, Sie können FragmentStatePagerAdapter anstelle von FragmentPageAdapter verwenden. Es werden Fragmente für Sie entfernt.

PS. Entschuldigen Sie die Verwendung der Antwort anstelle des Kommentars, aber mein Ruf ist zu niedrig.

37
Leszek

Ich bin gerade auf dasselbe Problem gestoßen. Ich hatte ein Fragment, das ein ViewPager von Fragments beherbergen musste. Wenn ich ein anderes Fragment auf mein ViewPagerFragment stapelte und dann zurücklegte, würde ich ein IllegalStateException bekommen. Nachdem ich die Protokolle geprüft hatte (beim Stapeln einer neuen Fragment), stellte ich fest, dass meine ViewPagerFragment ihre Lebenszyklusmethoden durchlaufen würde, um anzuhalten und zu zerstören, jedoch ihre Kinder Fragments in der ViewPager würde in onResume bleiben. Ich erkannte, dass die Kinder Fragments von FragmentManager für ViewPagerFragment verwaltet werden sollten, nicht von FragmentManager von Activity.

Ich verstehe zu dem Zeitpunkt, dass die obigen Antworten darin bestehen, die Einschränkungen von Fragments zu umgehen, die keine Kinder Fragments haben können. Jetzt, da die neueste Unterstützungsbibliothek die Fragment-Verschachtelung unterstützt, müssen Sie den Adapter für Ihre ViewPager -Einstellung nicht mehr festlegen und getChildFragmentManager() reicht aus. Das hat bisher perfekt für mich funktioniert.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager) mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getChildFragmentManager());
    mViewPager.setAdapter(mAdapter);

    return mView;
}
24
Steven Byle

Ich habe Handler.post() verwendet, um den Adapter außerhalb der ursprünglichen Fragmenttransaktion festzulegen:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mViewPager.setAdapter(mAdapter);     
        }
    });        
}
19
inazaruk

Dieses Problem ist beim Versuch aufgetreten, den viewPager-Adapter auf dem TabIndicator in ViewCreated zu initialisieren. Nachdem ich im Internet darüber gelesen hatte, wurde mir klar, dass dies daran liegen könnte, dass das Fragment noch nicht zur Aktivität hinzugefügt wurde. Also habe ich den Initialisierungscode auf onStart () des Fragments verschoben. Dies sollte Ihr Problem lösen. Aber nicht für mich bekam ich immer noch dasselbe Problem.

Das lag jedoch daran, dass ich in meinem Code versucht hatte, die normale asynchrone Ausführung einer anstehenden Task zu umgehen, indem sie explizit zu executePendingTransactions () aufrief, nachdem alles blockiert war

0
Sanket

Entsprechend der Dokumentation: https://developer.Android.com/reference/Android/app/Fragment.html#getChildFragmentManager ()

Wenn Sie das Verschachtelungsfragment verwalten möchten, müssen Sie getChildFragmentManager anstelle von getFragmentManager verwenden.

0

Beim Laden des übergeordneten Fragments wird mir eine IllegalStateException mit der folgenden Meldung angezeigt: Java.lang.IllegalStateException: Rekursiver Eintrag zum Ausführen von PendingTransactions.

Einige Nachforschungen haben mich zu der Schlussfolgerung geführt, dass das System keine Fragmente innerhalb eines anderen Fragments anzeigen kann. Allerdings scheint es Anzeichen dafür zu geben, dass es möglich ist, genau dies mit der Verwendung eines ViewPagers zu tun (Ein Fehler in ViewPager, der ihn mit einem anderen Fragment verwendet ).

legen Sie die ID für ViewPager explizit fest.

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      mView = inflater.inflate(R.layout.team_card_master, container, false);
      mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
      mViewPager.setId(100);

      final Button button = (Button)mView.findViewById(R.id.load_viewpager_button);
      button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
          mViewPager.setAdapter(mAdapter);
          button.setVisibility(View.GONE);
        }
      });
      mAdapter = new ViewPagerAdapter(getFragmentManager());
      mViewPager.setAdapter(mAdapter);

      return mView;
    }

Sie können eine ID in Ihren XML-Ressourcen anstelle einer magischen Zahl 100 verwenden.

<resources>
  <item name="Id_For_ViewPager" type="id"/>
</resources>

und setId (R.Id_For_ViewPager).

Weitere Informationen finden Sie in der Quelle FragmentManager.Java.

https://github.com/Android/platform_frameworks_support/blob/master/v4/Java/Android/support/v4/app/FragmentManager.Java#L900

Oder sehen Sie diese Seite (Japanisch). Die ursprüngliche Idee stammt von ihr, nicht von mir. http://y-anz-m.blogspot.jp/2012/04/androidfragment-viewpager-id.html

0
Kugyo

Statt den Adapter in AsyncTask oder einem anderen Handler festzulegen, schreiben Sie einfach diesen Teil des Codes in den Abschnitt onResume ()

So tun Sie:

  • Lassen Sie den Übergang des Hauptfragments abgeschlossen sein.
  • Das untergeordnete Fragment ohne Hintergrundaufgabe anzeigen.

Der Code von onResume () lautet in Ihrem Fall wie folgt:

@Override
public void onResume() {
    super.onResume();
    if(mViewPager.getAdapter()==null||mViewPager.getAdapter().getCount()==0)
    mViewPager.setAdapter(mAdapter);
}

Auch in onCreateView Anstelle von

mAdapter = new ViewPagerAdapter(getFragmentManager());

Ersetzen mit

mAdapter = new ViewPagerAdapter(getChildFragmentManager());
0
Karan

Mit diesem genialen Beitrag von Thomas Amssler: http://tamsler.blogspot.nl/2011/11/Android-viewpager-and-fragments-part-ii.html

Iv'e hat einen Adapter erstellt, mit dem alle Arten von Fragmenten erstellt werden können. Der Adapter selbst sieht folgendermaßen aus: 

public abstract class EmbeddedAdapter extends FragmentStatePagerAdapter {

private SparseArray<WeakReference<Fragment>>    mPageReferenceMap   = new SparseArray<WeakReference<Fragment>>();
private ArrayList<String> mTabTitles;

public abstract Fragment initFragment(int position);

public EmbeddedAdapter(FragmentManager fm, ArrayList<String> tabTitles) {
    super(fm);
    mTabTitles = tabTitles;
}

@Override
public Object instantiateItem(ViewGroup viewGroup, int position) {
    mPageReferenceMap.put(Integer.valueOf(position), new WeakReference<Fragment>(initFragment(position)));
    return super.instantiateItem(viewGroup, position);
}

@Override
public int getCount() {
    return mTabTitles.size();
}

@Override
public CharSequence getPageTitle(int position) {
    return mTabTitles.get(position);
}

@Override
public Fragment getItem(int pos) {
    return getFragment(pos);
}

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

public Fragment getFragment(int key) {

    WeakReference<Fragment> weakReference = mPageReferenceMap.get(key);

    if (null != weakReference) {

        return (Fragment) weakReference.get();

    } else {
        return null;
    }
}

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

}

Um den Adapter zu verwenden, müssen Sie Folgendes tun:

private void setAdapter() {

    if(mAdapter == null) mAdapter = new EmbeddedAdapter(getActivity().getSupportFragmentManager(), mTabTitles) {

        @Override
        public Fragment initFragment(int position) {

            Fragment fragment;

            if(position == 0){

                // A start fragment perhaps?
                fragment = StartFragment.newInstance(mBlocks);

            }else{

                // Some other fragment
                fragment = PageFragment.newInstance(mCategories.get((position)));
            }
            return fragment;
        }
    };

    // Have to set the adapter in a handler
    Handler handler = new Handler();
    handler.post(new Runnable() {

        @Override
        public void run() {

            mViewPager.setVisibility(View.VISIBLE);
            mPagerTabStrip.setVisibility(View.VISIBLE);
            mAdapter.notifyDataSetChanged();
        }
    });
}

Beachten Sie, dass alle Fragmente Folgendes verwenden:

setRetainInstance(true);
0
Slickelito