Ottenere l'istanza del frammento corrente nel viewpager


210

Di seguito è riportato il mio codice che ha 3 Fragment classesincorporato ciascuno con ciascuna delle 3 schede ViewPager. Ho un'opzione di menu. Come mostrato in onOptionsItemSelected(), selezionando un'opzione, devo aggiornare il frammento che è attualmente visibile. Per aggiornarlo devo chiamare un metodo che appartiene alla classe dei frammenti. Qualcuno può suggerire come chiamare quel metodo?

public class MainActivity  extends ActionBarActivity {

     ViewPager ViewPager;
     TabsAdapter TabsAdapter;

     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            ViewPager = new ViewPager(this);
            ViewPager.setId(R.id.pager);
            setContentView(ViewPager);

            final ActionBar bar = getSupportActionBar();

            bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

            //Attaching the Tabs to the fragment classes and setting the tab title.
            TabsAdapter = new TabsAdapter(this, ViewPager);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
                    FragmentClass1.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
              FragmentClass2.class, null);
            TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
              FragmentClass3.class, null);


            if (savedInstanceState != null) {
                bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
            }

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {

            switch (item.getItemId()) {

            case R.id.addText:

           **// Here I need to call the method which exists in the currently visible Fragment class**

                    return true;

            }

            return super.onOptionsItemSelected(item);
        }


     @Override
     protected void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
            outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());

     }

     public static class TabsAdapter extends FragmentPagerAdapter
      implements ActionBar.TabListener, ViewPager.OnPageChangeListener {

      private final Context mContext;
            private final ActionBar mActionBar;
            private final ViewPager mViewPager;
            private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

            static final class TabInfo {
                private final Class<?> clss;
                private final Bundle args;

                TabInfo(Class<?> _class, Bundle _args) {
                    clss = _class;
                    args = _args;
                }
            }

      public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
       super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = activity.getSupportActionBar();
                mViewPager = pager;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
            }

      public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                TabInfo info = new TabInfo(clss, args);
                tab.setTag(info);
                tab.setTabListener(this);
                mTabs.add(info);
                mActionBar.addTab(tab);
                notifyDataSetChanged();

            }

      @Override
      public void onPageScrollStateChanged(int state) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onPageSelected(int position) {
       // TODO Auto-generated method stub
       mActionBar.setSelectedNavigationItem(position);
      }

      @Override
      public void onTabReselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public void onTabSelected(Tab tab, FragmentTransaction ft) {
       Object tag = tab.getTag();
                for (int i=0; i<mTabs.size(); i++) {
                    if (mTabs.get(i) == tag) {
                        mViewPager.setCurrentItem(i);

                    }
                }

                tabPosition = tab.getPosition();
      }

      @Override
      public void onTabUnselected(Tab tab, FragmentTransaction ft) {
       // TODO Auto-generated method stub

      }

      @Override
      public Fragment getItem(int position) {
       TabInfo info = mTabs.get(position);
                return Fragment.instantiate(mContext, info.clss.getName(), info.args);
      }

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

     }

    }

Supponiamo di seguito la classe di frammenti con il metodo updateList()che voglio chiamare:

 public class FragmentClass1{

    ArrayList<String> originalData;


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

          View fragmentView = inflater.inflate(R.layout.frag1, container, false);

          originalData = getOriginalDataFromDB();

          return fragmentView;

         }


    public void updateList(String text)
    {
       originalData.add(text);
       //Here I could do other UI part that need to added
    }
}

quale metodo di frammento vuoi chiamare?
Biraj Zalavadia,

@BirajZalavadia Il mio metodo definito, che contiene un parametro e utilizza le variabili di istanza di quella classe di frammento che sono già state inizializzate durante la creazione di una vista pari.
Rick

1
puoi dare il nome della classe dei tuoi frammenti che sono in viewpager?
Biraj Zalavadia,


Il modo più semplice per accedere ai frammenti visibili sarebbe attraverso stackoverflow.com/questions/7379165/… , guarda le prime due risposte.
Luksprog,

Risposte:


205

selezionando un'opzione, devo aggiornare il frammento attualmente visibile.

Un modo semplice per farlo è usare un trucco relativo FragmentPagerAdapterall'implementazione:

case R.id.addText:
     Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
     // based on the current position you can then cast the page to the correct 
     // class and call the method:
     if (ViewPager.getCurrentItem() == 0 && page != null) {
          ((FragmentClass1)page).updateList("new item");     
     } 
return true;

Ripensare la convenzione di denominazione delle variabili, usando come nome della variabile il nome della classe è molto confuso (quindi no ViewPager ViewPager, usare ViewPager mPagerad esempio).


23
Quel frammento è tag a prova di futuro, se l'API cambia?
Maarten,

7
@Maarten No, è solo un hack comune che è stato usato da quando è apparso l'adattatore (e il suo codice sorgente era disponibile), non è ancora cambiato. Se si desidera qualcosa di più affidabile, è necessario utilizzare altre opzioni, in particolare l'override del instantiateItem()metodo e l'ottenimento di riferimenti ai frammenti appropriati.
Luksprog,

5
Dopo ore di frustrazione e chiedendo le pagine direttamente dal mAdapter.getItem(position) , fantastico ... Almeno ora so che le altre 8512 prove non hanno funzionato. Grazie
Diolor,

29
Nota che non funziona se usi FragmentStatePagerAdapter anziché FragmentPagerAdapter.
Shawn Lauzon,

3
@ShawnLauzon FragmentStatePagerAdapter ha un'implementazione diversa, nel suo caso si chiama il metodo instantiateItem () per ottenere i frammenti visibili.
Luksprog

155
    public class MyPagerAdapter extends FragmentPagerAdapter {
        private Fragment mCurrentFragment;

        public Fragment getCurrentFragment() {
            return mCurrentFragment;
        }
//...    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (getCurrentFragment() != object) {
                mCurrentFragment = ((Fragment) object);
            }
            super.setPrimaryItem(container, position, object);
        }
    }

29
Google dovrebbe fornire FragmentPageAdapter.getCurrentPrimaryItem () restituendo mCurrentPrimaryItem.
Eugene,

1
Uso anche questa tecnica e definisco un PagerFragment con metodi onPageSelected/ onPageDeselectede lo estendo a tutti i miei frammenti di cercapersone. Quindi setPrimaryitempuò chiamare questi metodi in modo appropriato quando l'utente passa a una nuova pagina. Ciò significa che è possibile implementare una strategia più pigra per il caricamento di dati in pagine che non sono nemmeno mostrate. Dovresti comunque tenere presente che durante la transizione di pagina sembra meglio se la pagina successiva è già popolata di dati, quindi il caricamento lento di tutti i dati onPageSelectedpotrebbe non essere l'ideale.
JHH il

3
Perché la ifdichiarazione? Il frammento richiama semplicemente il equalsmetodo dell'oggetto, che è un confronto superficiale. Quindi perché non chiamare sempre mCurrentFragment = ((Fragment) object);?
Overclover

provato e funziona benissimo, basta lanciare getCurrentFragment () sullo specifico frammento che dovrebbe
PhilipJ

113

Prima di tutto tenere traccia di tutte le pagine di frammenti "attive". In questo caso, si tiene traccia delle pagine dei frammenti in FragmentStatePagerAdapter, utilizzato da ViewPager.

@Override
public Fragment getItem(int index) {
    Fragment myFragment = MyFragment.newInstance();
    mPageReferenceMap.put(index, myFragment);
    return myFragment;
}

Per evitare di mantenere un riferimento a pagine di frammenti "inattive", è necessario implementare il metodo destroyItem (...) di FragmentStatePagerAdapter:

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

e quando è necessario accedere alla pagina attualmente visibile, chiamare quindi:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

Dove il metodo getFragment (int) di MyAdapter si presenta così:

public MyFragment getFragment(int key) {
    return mPageReferenceMap.get(key);
}

Spero possa essere d'aiuto!


Puoi per favore spiegare chiaramente? Dove devo conservare questa classe FragmentStatePagerAdapter nel mio codice? A proposito, ho 3 classi di frammenti, non una singola MyFragmentClass.
Rick

7
Ancora meglio se aggiorni mPageReferenceMap in instantiateItem invece di getItem perché funziona anche dopo il cambio di orientamento. '@Override Public Object instantiateItem (contenitore ViewGroup, int position) {Fragment fragment = (Fragment) Super.instantiateItem (container, position); mPageReferenceMap.put (posizione, frammento); frammento di ritorno; } "
pmellaaho,

Che tipo è mPageReferenceMap?
DoruAdryan,

10
Questa risposta è davvero pessima! Non si dovrebbe conservare manualmente la cache di un ViewPager poiché lo gestisce da solo. ViewPager decide quando il frammento deve essere allocato o meno, cosa mettere in pausa e quando, mantenere un riferimento su ogni frammento aggiungerà un sovraccarico inutile e non sarà ottimizzato per la memoria.
Livio,

3
Ho provato questo approccio ma sfortunatamente non funziona quando viene ricreata l'attività. Su Android N e versioni successive, puoi vedere questo quando usi la funzione multiwindow. Quando l'app è aperta, tieni premuto a lungo il pulsante "recenti" (quello quadrato). L'attività e il frammento vengono ricreati da savedInstanceState, viene ricreato l'adattatore (quindi mPageReferenceMap è ora vuoto), ma getItem non viene richiamato nuovamente. La mappa rimane vuota, quindi adapter.getFragment (indice) andrà in crash.
Martin Konicek,

102

Questo è l'unico modo in cui non ottengo NullPointerException per le variabili di istanza di quelle particolari classi di frammenti. Questo potrebbe essere utile per gli altri che si sono bloccati nella stessa cosa. In onOptionsItemSelected (), ho codificato il modo seguente:

if(viewPager.getCurrentItem() == 0) {
    FragmentClass1 frag1 = (FragmentClass1)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag1.updateList(text); 
} else if(viewPager.getCurrentItem() == 1) {
    FragmentClass2 frag2 = (FragRecentApps)viewPager
                            .getAdapter()
                            .instantiateItem(viewPager, viewPager.getCurrentItem());
    frag2.updateList(text);
}

3
Penso che questa sia la risposta più corretta: allinearsi con il design FragmentStatePagerAdaptersenza sovrascrivere alcun codice. In effetti, dovrebbe essere semplice come una funzione appena restituita viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem()).
John Pang,

39

FragmentStatePagerAdapter ha un metodo pubblico con il nome instantiateItem che restituisce il frammento in base ai valori dei parametri specificati, questo metodo ha due parametri ViewGroup (ViewPager) e posizione.

public Object instantiateItem(ViewGroup container, int position);

Usato questo metodo per ottenere il frammento di posizione specificato,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

5
Ma questo non restituisce l'attuale frammento già istanziato, ma invece uno nuovo, no? Quindi nome "istanzia" ...
Ixx

1
@Ixx No, non crea un nuovo frammento. Penso che il nome del metodo non sia corretto qui.
Bugs Happen

15

So che è troppo tardi ma ho modi molto semplici per farlo,

// per frammento a 0 possition

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

10

Ci sono molte risposte qui che non affrontano davvero il fatto fondamentale che non c'è davvero NESSUN MODO per farlo in modo prevedibile, e in un modo che non ti porta a spararti nel piede ad un certo punto in futuro.

FragmentStatePagerAdapterè l'unica classe che sa come accedere in modo affidabile ai frammenti tracciati dal FragmentManager- qualsiasi tentativo di provare a indovinare l'ID o il tag del frammento non è affidabile, a lungo termine. E i tentativi di tracciare manualmente le istanze probabilmente non funzioneranno bene quando lo stato viene salvato / ripristinato, perché FragmentStatePagerAdapterpotrebbe non richiamare i callback quando ripristina lo stato.

L'unica cosa che sono stato in grado di far funzionare è la copia del codice FragmentStatePagerAdaptere l'aggiunta di un metodo che restituisce il frammento, data una posizione ( mFragments.get(pos)). Si noti che questo metodo presuppone che il frammento sia effettivamente disponibile (cioè era visibile ad un certo punto).

Se sei particolarmente avventuroso, puoi usare la riflessione per accedere agli elementi mFragmentsdell'elenco privato , ma poi torniamo al punto di partenza (il nome dell'elenco non è garantito per rimanere lo stesso).


1
per gestire "non funziona bene quando lo stato viene salvato / ripristinato", sostituisco il metodo saveState (). In modo che il cercapersone non salvi alcun frammento quando l'attività viene messa in pausa. Funziona.
AntoineP

2
Ciò si aggiunge al patchwork, senza risolvere il problema di fondo. Non sto sostenendo che non funziona, solo che non è una buona implementazione.
Melllvar,

8
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

Trasmetti l'istanza recuperata da sopra la riga sul frammento su cui vuoi lavorare. Funziona perfettamente.

viewPager

è l'istanza del cercapersone che gestisce i frammenti.


Funziona solo se tutte le pagine sono caricate come frammento. Quando ad esempio è presente un tablayout con molte schede / pagine, non tutte vengono caricate, quindi ciò potrebbe sollevare un'eccezione indexoutofbounce.
progNewbie,

@progNewbie sì, sarà necessario un codice aggiuntivo.
Gaurav Pangam,

@progNewbie La risposta di Evgeny qui sotto gestirà quella situazione penso
Gaurav Pangam,

7

selezionando un'opzione, devo aggiornare il frammento attualmente visibile.

Per ottenere un riferimento al frammento attualmente visibile, supponi di avere un riferimento a ViewPagercome mPager. Quindi i seguenti passaggi otterranno un riferimento a currentFragment:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

L'unico cast usato nella linea 3 è valido di solito. FragmentStatePagerAdapterè un adattatore utile per un ViewPager.


7

Il modo migliore per farlo, chiama CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter () .instantiateItem (viewPager, viewPager.getCurrentItem ()); Istituirà nuovamente l'istanza del frammento chiamante, in modo da non generare un'eccezione puntatore null e chiamare qualsiasi metodo di quel frammento.


6

Frammento attuale:

Funziona se hai creato un progetto con il modello della barra delle schede dei frammenti.

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

Si noti che funziona con l'implementazione predefinita del modello di attività a schede.


30
Questo dipende dalla tua implementazione di getItem () - potrebbe restituire una nuova istanza del frammento, che probabilmente non è ciò che desideri.
Tom,

Ecco come lo fai. se si ha ancora la configurazione predefinita quando si crea un progetto tabor con frammenti. nessuno aveva questa soluzione. quindi ho pensato che sarebbe stato d'aiuto.
Hasan,

3

Ho usato il seguente:

 int index = vpPager.getCurrentItem();
 MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
 MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

1
Ciò si basa su un'implementazione del cercapersone personalizzata dalla risposta trovata qui: stackoverflow.com/questions/8785221/…
Tom Redman

1
Questo è esattamente quello che stavo cercando di fare ma senza sapere quali metodi scavalcare, avrei perso ore - grazie!
Bron Davies,

2

FragmentStatePagerAdapterha una variabile di istanza privata chiamata mCurrentPrimaryItemdi tipo Fragment. Ci si può solo chiedere perché gli sviluppatori Android non lo abbiano fornito con un getter. Questa variabile è istanziata nel setPrimaryItem()metodo. Quindi, sovrascrivi questo metodo in modo tale da ottenere il riferimento a questa variabile. Ho semplicemente finito per dichiarare il mio mCurrentPrimaryIteme copiarne il contenutosetPrimaryItem() mio override.

Nella tua implementazione di FragmentStatePagerAdapter:

private Fragment mCurrentPrimaryItem = null;

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    Fragment fragment = (Fragment)object;
    if (fragment != mCurrentPrimaryItem) {
        if (mCurrentPrimaryItem != null) {
            mCurrentPrimaryItem.setMenuVisibility(false);
            mCurrentPrimaryItem.setUserVisibleHint(false);
        }
        if (fragment != null) {
            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
        }
        mCurrentPrimaryItem = fragment;
    }
}

public TasksListFragment getCurrentFragment() {
    return (YourFragment) mCurrentPrimaryItem;
}

2

È possibile definire il PagerAdaptercome questo allora si sarà in grado di ottenere qualsiasi Fragmentin ViewPager.

private class PagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();

    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

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

    public void addFragment(Fragment fragment) {
        mFragmentList.add(fragment);
    }
}

Per ottenere la corrente Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());

2

Quando utilizziamo viewPager, un buon modo per accedere all'istanza del frammento in attività è instantiateItem (viewpager, indice). // indice- indice del frammento di cui si desidera l'istanza.

ad esempio accedo all'istanza di frammento di 1 indice-

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);

if (fragment != null && fragment instanceof MyFragment) {      
 ((MyFragment) fragment).callYourFunction();

}

2

Nella mia precedente implementazione ho archiviato un elenco di frammenti secondari per poterli accedere in seguito, ma si è rivelata un'implementazione errata che causa enormi perdite di memoria.

Finisco usando il instantiateItem(...)metodo per ottenere l'attuale frammento:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

O per ottenere qualsiasi altro frammento in posizione:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

Dalla documentazione :

Crea la pagina per la posizione specificata. L'adattatore è responsabile per l'aggiunta della vista al contenitore indicato qui, anche se deve assicurarsi che ciò avvenga solo quando ritorna da finishUpdate (ViewGroup).


Breve e pulito, grazie
JimmyFlash

1

Ho avuto lo stesso problema e l'ho risolto usando questo codice.

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

Basta sostituire il nome MyFragment con il nome del frammento e aggiungere l'id del contenitore dei frammenti.


1

Questo è più a prova di futuro della risposta accettata:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    /* ------------------------------------------------------------------------------------------ */
    // region Private attributes :

    private Context _context;
    private FragmentManager _fragmentManager;
    private Map<Integer, String> _fragmentsTags = new HashMap<>();

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region Constructor :

    public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {

        super(fragmentManager);

        _context = context;
        _fragmentManager = fragmentManager;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */



    /* ------------------------------------------------------------------------------------------ */
    // region FragmentPagerAdapter methods :

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

    @Override
    public Fragment getItem(int position) {

        if(_fragmentsTags.containsKey(position)) {

            return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
        }
        else {

            switch (position) {

                case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
                case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
            }
        }

        return null;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        // Instantiate the fragment and get its tag :
        Fragment result = (Fragment) super.instantiateItem(container, position);
        _fragmentsTags.put(position, result.getTag());

        return result;
    }

    // endregion
    /* ------------------------------------------------------------------------------------------ */
}

Invece dovresti usare WeakHashMap.
Prakash Nadar,

1

Lo scenario in questione è meglio servito da ciascun frammento aggiungendo le proprie voci di menu e gestendo direttamente onOptionsItemSelected (), come descritto nella documentazione ufficiale . È meglio evitare trucchi non documentati.


Questa risposta potrebbe utilizzare ulteriori dettagli su come farlo effettivamente. In che modo l'aggiunta di una voce di menu risolve il ViewPagerproblema?
Suragch,

Il problema @Suragch ViewPager esiste se gli eventi di menu sono gestiti all'interno di Attività che ospita frammenti e non esiste se gli eventi sono gestiti all'interno del frammento stesso. Il collegamento mostra come un frammento può aggiungere le proprie voci di menu.
Y2i,

1

Dopo aver letto tutti i commenti e le risposte ho intenzione di spiegare una soluzione ottimale per questo problema. L'opzione migliore è la soluzione di @ rik, quindi il mio miglioramento si basa sulla sua.

Invece di dover chiedere a ogni FragmentClass come

if(FragmentClass1){
   ...
if(FragmentClass2){
   ...
}

Crea la tua interfaccia e crea i frammenti di tuo figlio implementandola, qualcosa del genere

public interface MyChildFragment {
    void updateView(int position);
}

Quindi, puoi fare qualcosa del genere per avviare e aggiornare i tuoi frammenti interiori.

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());

if (childFragment != null) {
   ((MyChildFragment) childFragment).updateView();
}

PS Fai attenzione a dove inserisci quel codice, se chiami insatiateItem prima che il sistema lo crei effettivamente il savedInstanceStateframmento del tuo figlio sarà nullo per questo

public void onCreate(@Nullable Bundle savedInstanceState){
      super(savedInstanceState)
}

Arresto anomalo dell'app.

In bocca al lupo


1

Sulla base di ciò che ha risposto a @chahat jain:

"Quando utilizziamo viewPager, un buon modo per accedere all'istanza del frammento in attività è instantiateItem (viewpager, indice). // indice-indice del frammento di cui vuoi l'istanza."

Se vuoi farlo in kotlin

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                if ( fragment is YourFragmentFragment)
                 {
                    //DO somthign 
                 }

0 all'istanza del frammento di 0

// ================================================ ========================= // // ##################### ######## Esempio di utilizzo ######################################## // // == ================================================== ===================== //

Ecco un esempio completo per avere una visione perdente

ecco il mio veiewPager nel file .xml

   ...
    <android.support.v4.view.ViewPager
                android:id="@+id/mv_viewpager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="5dp"/>
    ...

E l'attività domestica in cui inserisco la scheda

...
import kotlinx.android.synthetic.main.movie_tab.*

class HomeActivity : AppCompatActivity() {

    lateinit var  adapter:HomeTabPagerAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
       ...
    }



    override fun onCreateOptionsMenu(menu: Menu) :Boolean{
            ...

        mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
          ...

            override fun onQueryTextChange(newText: String): Boolean {

                if (mv_viewpager.currentItem  ==0)
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
                    if ( fragment is ListMoviesFragment)
                        fragment.onQueryTextChange(newText)
                }
                else
                {
                    val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
                    if ( fragment is ListShowFragment)
                        fragment.onQueryTextChange(newText)
                }
                return true
            }
        })
        return super.onCreateOptionsMenu(menu)
    }
        ...

}

0

Nella mia attività ho:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int pos) {
        currentPage = pos;//update current page
}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});



@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if(fragment instanceof Fragment1)
        fragments.put(0, fragment);
    if(fragment instanceof Fragment2)
        fragments.put(2, fragment);
    if(fragment instanceof Fragment3)
        fragments.put(3, fragment);
    if(fragment instanceof Fragment4)
        fragments.put(4, fragment);
}

Then I have the following method for getting the current fragment

public Fragment getCurrentFragment() {
    return fragments.get(currentPage);
}

0
final ViewPager.OnPageChangeListener onPageChangeListener =
    new ViewPager.OnPageChangeListener() {
      @Override public void onPageSelected(int position) {
        switch (position) {
          case 0:
            FragmentClass1 frag1 =
                (FragmentClass1) viewPager.getAdapter()
                    .instantiateItem(viewPager, viewPager.getCurrentItem());
            frag1.updateList("Custom text");
            break;
          case 1:
            break;
          case 2:
            break;
        }
      }

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

      }

      @Override public void onPageScrollStateChanged(int state) {
      }
    };


 viewPager.addOnPageChangeListener(onPageChangeListener);

viewPager.setAdapter(adapter);


viewPager.post(new Runnable() {
  @Override public void run() {
    onPageChangeListener.onPageSelected(viewPager.getCurrentItem());
  }
});

A volte il frammento potrebbe inviare un oggetto null, quindi è possibile eseguire un nuovo Runnable per risolvere il problema al primo caricamento.

Grazie Rick


Aggiungi un testo che spieghi perché questo codice risolve il problema del PO. Inoltre, date quante altre risposte ci sono, spiega perché questa risposta è migliore di quelle già fornite. Aiuta gli altri a capire.
APC il

0

Sostituisci setPrimaryItem dal tuo FragmentPagerAdapter: l'oggetto è il frammento visibile:

 @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            if (mCurrentFragment != object) {
                mCurrentFragment = (LeggiCapitoloFragment) object;
            }
            super.setPrimaryItem(container, position, object);
        }

0

Prendi semplicemente l'elemento corrente dal cercapersone e poi chiedi al tuo adattatore il frammento di quella posizione.

 int currentItem = viewPager.getCurrentItem();
    Fragment item = mPagerAdapter.getItem(currentItem);
    if (null != item && item.isVisible()) {
       //do whatever want to do with fragment after doing type checking
        return;
    }

3
E se getItemcrea una nuova istanza
Prakash Nadar il

0

Per ottenere il frammento corrente: ottenere la posizione in ViewPager nel vuoto pubblico onPageSelected (posizione int finale) , quindi

public PlaceholderFragment getFragmentByPosition(Integer pos){
    for(Fragment f:getChildFragmentManager().getFragments()){
        if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
            return (PlaceholderFragment) f;
        }
    }
    return null;
}

SECTNUM - argomento di posizione assegnato in PlaceholderFragment newInstance statico pubblico (int sectionNumber);di frammento

getChildFragmentManager () o getFragmentManager () - dipende dalla modalità di creazione di SectionsPagerAdapter


0

È possibile implementare un BroadcastReceiver nel frammento e inviare un intento da qualsiasi luogo. Il destinatario del frammento può ascoltare l'azione specifica e invocare il metodo dell'istanza.

Un avvertimento è assicurarsi che il componente Visualizza sia già istanziato e (e per alcune operazioni, come lo scorrimento di un elenco, ListView deve già essere reso).


0

Questo è l'hack più semplice:

fun getCurrentFragment(): Fragment? {
    return if (count == 0) null
    else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(codice kotlin)

Basta chiamare instantiateItem(viewPager, viewPager.getCurrentItem()e lanciarlo a Fragment. Il tuo articolo sarebbe già stato istanziato. Per essere sicuri di poter aggiungere un controllo pergetCount .

Funziona con entrambi FragmentPagerAdaptere FragmentStatePagerAdapter!


0

Se il tuo cercapersone si trova all'interno di un frammento, utilizza questo:

private fun getPagerCurrentFragment(): Fragment? {
    return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

Dov'è R.id.myViewPagerIdl'ID del ViewPager all'interno del layout xml.


Funziona solo con il normale FragmentPageAdapter e non con FragmentStatePageAdapter.
progNewbie,

0

È possibile dichiarare una matrice di frammenti come frammenti di registro

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
    // CURRENT FRAGMENT
    val registeredFragments = SparseArray<Fragment>()

    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        val fragment = super.instantiateItem(container, position) as Fragment
        registeredFragments.put(position, fragment)
        return fragment
    }

    override fun getItem(position: Int): Fragment {
        return when (position) {
            0 -> HomeFragment.newInstance()
            1 -> ConverterDashboardFragment.newInstance()
            2 -> CartFragment.newInstance()
            3 -> CustomerSupportFragment.newInstance()
            4 -> ProfileFragment.newInstance()
            else -> ProfileFragment.newInstance()
        }
    }

    override fun getCount(): Int {
        return 5
    }

}

Quindi puoi usarlo come

adapter?.let {
    val cartFragment = it.registeredFragments[2] as CartFragment?
    cartFragment?.myCartApi(true)
}

Se decidi di procedere in questo modo, dovresti anche implementare destroyItem () e rimuovere l'istanza distrutta da RegisterFragments, altrimenti avrai una perdita di memoria.
Dephinera,

Questo è un buon consiglio. Puoi apportare una modifica nella risposta.
Hamza Khan,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.