ViewPager e frammenti – quale è il modo giusto per memorizzare lo stato del frammento?

I frammenti sembrano essere molto belli per separare la logica UI in alcuni moduli. Ma insieme a ViewPager suo ciclo di vita è ancora nebbioso per me. Così i pensieri Guru sono molto necessari!

Modifica

Vedi una soluzione scoraggiante sotto 😉

  • Il dispositivo Android emulato non sincronizza ora / data dopo il ripristino di istantanea
  • Valore di dpi delle visualizzazioni di text "grandi", "medio" e "piccole" di android
  • Come scoprire quale vista è focalizzata?
  • Android che ottiene frammento che è in FragmentPagerAdapter
  • Volley fuori dall'errore di memory, tentativo strano di allocazione
  • L'altezza della vista Nested Recycler non avvolge il suo contenuto
  • Scopo

    L'attività principale ha un ViewPager con frammenti. Questi frammenti potrebbero implementare una logica poco diversa per altre attività (submain), per cui i dati dei frammenti vengono riempiti tramite un'interface di callback all'interno dell'attività. E tutto funziona bene al primo lancio, ma …

    Problema

    Quando l'attività viene ricreata (ad esempio sulla modifica dell'orientamento) così fanno i frammenti di ViewPager . Il codice (che troverai qui sotto) dice che each volta che si crea l'attività cerco di creare una nuova adattatore di frammenti ViewPager uguale a frammenti (forse questo è il problema), ma FragmentManager ha già tutti questi frammenti memorizzati da qualche parte (where?) e inizia il meccanismo di ricreazione per quelli. Quindi il meccanismo di ricreazione chiama il frammento "vecchio" onAttach, onCreateView ecc. Con la mia chiamata di interface di richiamata per avviare i dati tramite il metodo implementato dell'attività. Ma questo metodo indica il frammento appena creato che viene creato tramite il metodo OnCreate di Activity.

    Problema

    Forse sto utilizzando templates sbagliati, ma anche il libro Android 3 Pro non ne ha molto. Quindi, per favore , mi dia un pugno e metti in evidenza come farlo nel modo giusto. Grazie molto!

    Codice

    Attività principale

     public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener { private MessagesFragment mMessagesFragment; @Override protected void onCreate(Bundle savedInstanceState) { Logger.d("Dash onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_container); new DefaultToolbar(this); // create fragments to use mMessagesFragment = new MessagesFragment(); mStreamsFragment = new StreamsFragment(); // set titles and fragments for view pager Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>(); screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment()); screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment); // instantiate view pager via adapter mPager = (ViewPager) findViewById(R.id.viewpager_pager); mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager()); mPager.setAdapter(mPagerAdapter); // set title indicator TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles); indicator.setViewPager(mPager, 1); } /* set of fragments callback interface implementations */ @Override public void onMessageInitialisation() { Logger.d("Dash onMessageInitialisation"); if (mMessagesFragment != null) mMessagesFragment.loadLastMessages(); } @Override public void onMessageSelected(Message selectedMessage) { Intent intent = new Intent(this, StreamActivity.class); intent.putExtra(Message.class.getName(), selectedMessage); startActivity(intent); } 

    BasePagerActivity aka helper

     public class BasePagerActivity extends FragmentActivity { BasePagerAdapter mPagerAdapter; ViewPager mPager; } 

    Adattatore

     public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider { private Map<String, Fragment> mScreens; public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) { super(fm); this.mScreens = screenMap; } @Override public Fragment getItem(int position) { return mScreens.values().toArray(new Fragment[mScreens.size()])[position]; } @Override public int getCount() { return mScreens.size(); } @Override public String getTitle(int position) { return mScreens.keySet().toArray(new String[mScreens.size()])[position]; } // hack. we don't want to destroy our fragments and re-initiate them after @Override public void destroyItem(View container, int position, Object object) { // TODO Auto-generated method stub } } 

    Frammento

     public class MessagesFragment extends ListFragment { private boolean mIsLastMessages; private List<Message> mMessagesList; private MessageArrayAdapter mAdapter; private LoadMessagesTask mLoadMessagesTask; private OnMessageListActionListener mListener; // define callback interface public interface OnMessageListActionListener { public void onMessageInitialisation(); public void onMessageSelected(Message selectedMessage); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // setting callback mListener = (OnMessageListActionListener) activity; mIsLastMessages = activity instanceof DashboardActivity; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { inflater.inflate(R.layout.fragment_listview, container); mProgressView = inflater.inflate(R.layout.listrow_progress, null); mEmptyView = inflater.inflate(R.layout.fragment_nodata, null); return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // instantiate loading task mLoadMessagesTask = new LoadMessagesTask(); // instantiate list of messages mMessagesList = new ArrayList<Message>(); mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList); setListAdapter(mAdapter); } @Override public void onResume() { mListener.onMessageInitialisation(); super.onResume(); } public void onListItemClick(ListView l, View v, int position, long id) { Message selectedMessage = (Message) getListAdapter().getItem(position); mListener.onMessageSelected(selectedMessage); super.onListItemClick(l, v, position, id); } /* public methods to load messages from host acitivity, etc... */ } 

    Soluzione

    La soluzione scoraggiante è salvare i frammenti all'interno di onSaveInstanceState (dell'attività host) con putFragment e inserirli all'interno di onCreate tramite getFragment. Ma ho ancora una strana sensazione che le cose non dovrebbero funzionare così … Vedi codice qui sotto:

      @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); getSupportFragmentManager() .putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment); } protected void onCreate(Bundle savedInstanceState) { Logger.d("Dash onCreate"); super.onCreate(savedInstanceState); ... // create fragments to use if (savedInstanceState != null) { mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment( savedInstanceState, MessagesFragment.class.getName()); StreamsFragment.class.getName()); } if (mMessagesFragment == null) mMessagesFragment = new MessagesFragment(); ... } 

  • Risorse $ NotFoundException: La risorsa non è un disegno (colore o path)?
  • come risolvere INSTALL_FAILED_DEXOPT questo errore?
  • Sostituisci getMap con getMapAsync
  • L'inserimento di text in SearchView non viene mostrato
  • super.onActivityResult all'interno della class dell'adattatore? android
  • Android TabLayout: distribuisci in modo uniforms
  • 10 Solutions collect form web for “ViewPager e frammenti – quale è il modo giusto per memorizzare lo stato del frammento?”

    Quando FragmentPagerAdapter aggiunge un frammento a FragmentManager, utilizza un tag speciale sulla base della posizione particolare in cui verrà collocato il frammento. FragmentPagerAdapter.getItem(int position) viene chiamato solo quando non esiste un frammento per quella posizione. Dopo aver ruotato, Android avrà notato che ha già creato / salvato un frammento per questa particolare posizione e quindi cerca semplicemente di riconnettersi con FragmentManager.findFragmentByTag() , invece di creare una nuova. Tutto questo viene libero quando si utilizza il FragmentPagerAdapter ed è il motivo per cui è solito avere il codice di initialization del frammento all'interno del getItem(int) .

    Anche se non usiamo un FragmentPagerAdapter , non è una buona idea creare un nuovo frammento each volta in Activity.onCreate(Bundle) . Come hai notato, quando un frammento viene aggiunto al FragmentManager, verrà ricreato per te dopo la rotazione e non c'è bisogno di aggiungere di nuovo. Fare così è una causa comune di errori quando si lavora con i frammenti.

    Un approccio usuale quando si lavora con i frammenti è questo:

     protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... CustomFragment fragment; if (savedInstanceState != null) { fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag"); } else { fragment = new CustomFragment(); getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit(); } ... } 

    Quando si utilizza un FragmentPagerAdapter , si abbandona la gestione dei frammenti alla scheda e non è necessario eseguire i passaggi di cui sopra. Per impostazione predefinita, verrà caricato solo un frammento di fronte e dietro la posizione corrente (anche se non li distrugge a less che non si utilizzi FragmentStatePagerAdapter ). Questo è controllato da ViewPager.setOffscreenPageLimit (int) . A causa di questo, i methods di chiamata diretta sui frammenti esterni dell'adattatore non sono garantiti per essere validi, perché potrebbero non essere ancora vivi.

    Per tagliare una lunga storia breve, la soluzione per utilizzare il putFragment per get un riferimento in seguito non è così pazzo, e non così diverso dal normale modo di utilizzare frammenti comunque (sopra). È difficile get un riferimento altrimenti perché il frammento viene aggiunto dall'adattatore, e non personalmente. Basta fare in modo che il file offscreenPageLimit sia abbastanza alto per caricare i frammenti desiderati in qualsiasi momento, poiché ti basterai affidarlo a essere presente. Questo bypassa le capacità di caricamento pigro del ViewPager, ma sembra essere quello che desideri per la tua applicazione.

    Un altro approccio è quello di ignorare FragmentPageAdapter.instantiateItem(View, int) e salvare un riferimento al frammento restituito dalla chiamata super prima di restituirlo (ha la logica di trovare il frammento, se già presente).

    Per un'image più completa, esaminare alcune delle origini di FragmentPagerAdapter (breve) e ViewPager (lungo).

    Voglio offrire una soluzione che si espande sulla risposta meravigliosa di antonyt e la menzione di FragmentPageAdapter.instantiateItem(View, int) per salvare i riferimenti ai Fragments creati in modo da poterli lavorare in seguito. Questo dovrebbe anche funzionare con FragmentStatePagerAdapter ; vedere le note per i dettagli.


    Ecco un semplice esempio di come get un riferimento ai Fragments restituiti da FragmentPagerAdapter che non si basa sui tags interni impostati sui Fragments . La chiave è quella di ignorare instantiateItem() e salvare i riferimenti in esso invece di in getItem() .

     public class SomeActivity extends Activity { private FragmentA m1stFragment; private FragmentB m2ndFragment; // other code in your Activity... private class CustomPagerAdapter extends FragmentPagerAdapter { // other code in your custom FragmentPagerAdapter... public CustomPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { // Do NOT try to save references to the Fragments in getItem(), // because getItem() is not always called. If the Fragment // was already created then it will be retrieved from the FragmentManger // and not here (ie getItem() won't be called again). switch (position) { case 0: return new FragmentA(); case 1: return new FragmentB(); default: // This should never happen. Always account for each position above return null; } } // Here we can finally safely save a reference to the created // Fragment, no matter where it came from (either getItem() or // FragmentManger). Simply save the returned Fragment from // super.instantiateItem() into an appropriate reference depending // on the ViewPager position. @Override public Object instantiateItem(ViewGroup container, int position) { Fragment createdFragment = (Fragment) super.instantiateItem(container, position); // save the appropriate reference depending on position switch (position) { case 0: m1stFragment = (FragmentA) createdFragment; break; case 1: m2ndFragment = (FragmentB) createdFragment; break; } return createdFragment; } } public void someMethod() { // do work on the referenced Fragments, but first check if they // even exist yet, otherwise you'll get an NPE. if (m1stFragment != null) { // m1stFragment.doWork(); } if (m2ndFragment != null) { // m2ndFragment.doSomeWorkToo(); } } } 

    o se si preferisce lavorare con i tags invece che le variables dei membri di class / i riferimenti ai Fragments è ansible anche afferrare i tags impostati da FragmentPagerAdapter nello stesso modo: NOTA: questo non si applica a FragmentStatePagerAdapter quanto non imposta i tags quando si crea i suoi Fragments .

     @Override public Object instantiateItem(ViewGroup container, int position) { Fragment createdFragment = (Fragment) super.instantiateItem(container, position); // get the tags set by FragmentPagerAdapter switch (position) { case 0: String firstTag = createdFragment.getTag(); break; case 1: String secondTag = createdFragment.getTag(); break; } // ... save the tags somewhere so you can reference them later return createdFragment; } 

    Tieni presente che questo metodo NON si basa sulla mimatura del tag interno impostato da FragmentPagerAdapter e invece utilizza le API appropriate per recuperarle. In questo modo, anche se il tag cambia nelle versioni future del SupportLibrary sarai ancora sicuro.


    Non dimenticare che, a seconda del disegno della tua Activity , i Fragments si sta tentando di lavorare potrebbero o non esistono ancora, per cui bisogna tenere conto di ciò eseguendo controlli null prima di utilizzare i tuoi riferimenti.

    Inoltre, se invece stai lavorando con FragmentStatePagerAdapter , allora non si desidera mantenere i riferimenti rigidi ai tuoi Fragments perché potrebbero essere presenti molti di essi e riferimenti duri potrebbero inutilmente mantenerli in memory. Invece salvare i riferimenti di Fragment nelle variables WeakReference anziché quelle standard. Come questo:

     WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment); // ...and access them like so Fragment firstFragment = m1stFragment.get(); if (firstFragment != null) { // reference hasn't been cleared yet; do work... } 

    Ho trovato un'altra soluzione relativamente semplice per la tua domanda.

    Come potete vedere dal codice sorgente FragmentPagerAdapter , i frammenti gestiti dall'archivio FragmentPagerAdapter nel FragmentManager sotto il tag generato utilizzando:

     String tag="android:switcher:" + viewId + ":" + index; 

    Il viewId è il container.getId() , il container è l'istanza ViewPager . L' index è la posizione del frammento. Quindi è ansible salvare l'id object outState :

     @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("viewpagerid" , mViewPager.getId() ); } @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); if (savedInstanceState != null) viewpagerid=savedInstanceState.getInt("viewpagerid", -1 ); MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this); mViewPager = (ViewPager) findViewById(R.id.pager); if (viewpagerid != -1 ){ mViewPager.setId(viewpagerid); }else{ viewpagerid=mViewPager.getId(); } mViewPager.setAdapter(titleAdapter); 

    Se si desidera comunicare con questo frammento, è ansible get se da FragmentManager , ad esempio:

     getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0") 

    Voglio offrire una soluzione alternativa per forse un caso leggermente diverso, poiché molte delle mie ricerche di risposte mi hanno portto a questo thread.

    Il mio caso – creo / aggiunge pagine dynamicmente e li scorcio in un ViewPager, ma quando sono ruotati (onConfigurationChange) finisco con una nuova pagina perché naturalmente si riceve una chiamata su OnCreate. Ma voglio continuare a fare riferimento a tutte le pagine che sono state create prima della rotazione.

    Problema – Non ho identificatori univoco per each frammento che creo, quindi l'unico modo per fare riferimento è stato quello di archiviare in qualche modo i riferimenti in un arrays da ripristinare dopo la modifica della rotazione / configuration.

    Soluzione alternativa – Il concetto fondamentale consisteva nel fatto che l'attività (che visualizza i frammenti) gestisce anche l'arrays di riferimenti ai frammenti esistenti, poiché questa attività può utilizzare i pacchetti in onSaveInstanceState

     public class MainActivity extends FragmentActivity 

    Quindi, all'interno di questa attività, dichiaro un membro privato a tenere traccia delle pagine aperte

     private List<Fragment> retainedPages = new ArrayList<Fragment>(); 

    Questo viene aggiornato each volta che onSaveInstanceState viene chiamato e ripristinato in onCreate

     @Override protected void onSaveInstanceState(Bundle outState) { retainedPages = _adapter.exportList(); outState.putSerializable("retainedPages", (Serializable) retainedPages); super.onSaveInstanceState(outState); } 

    … quindi una volta memorizzato, può essere recuperato …

     @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState != null) { retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages"); } _mViewPager = (CustomViewPager) findViewById(R.id.viewPager); _adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager()); if (retainedPages.size() > 0) { _adapter.importList(retainedPages); } _mViewPager.setAdapter(_adapter); _mViewPager.setCurrentItem(_adapter.getCount()-1); } 

    Queste erano le necessarie modifiche all'attività principale e quindi ho bisogno dei membri e dei methods all'interno del mio FragmentPagerAdapter affinché questo funzioni, quindi

     public class ViewPagerAdapter extends FragmentPagerAdapter 

    un costrutto identico (come mostrato in precedenza in MainActivity)

     private List<Fragment> _pages = new ArrayList<Fragment>(); 

    e questa sincronizzazione (come usato sopra in onSaveInstanceState) è supportta in modo specifico dai methods

     public List<Fragment> exportList() { return _pages; } public void importList(List<Fragment> savedPages) { _pages = savedPages; } 

    E poi, infine, nella class di frammentazione

     public class CustomFragment extends Fragment 

    per far funzionare tutto questo, ci sono stati due cambiamenti, in primo luogo

     public class CustomFragment extends Fragment implements Serializable 

    e poi aggiungerlo a Creare così i frammenti non vengono distrutti

     setRetainInstance(true); 

    Sono ancora in fase di avvolgere la mia testa intorno a Fragmenti e il ciclo di vita di Android, quindi caveat qui ci possono essere ridondanze / inefficienze in questo metodo. Ma funziona per me e spero possa essere utile per gli altri con casi simili alla mia.

    La mia soluzione è molto scortese ma funziona: essendo i miei frammenti creati dynamicmente dai dati conservati, rimuovo semplicemente tutto il frammento da PageAdapter prima di call super.onSaveInstanceState() e poi ricreandolo sulla creazione di attività:

     @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("viewpagerpos", mViewPager.getCurrentItem() ); mSectionsPagerAdapter.removeAllfragments(); super.onSaveInstanceState(outState); } 

    Non è ansible rimuoverli in onDestroy() , altrimenti si ottiene questa exception:

    java.lang.IllegalStateException: imansible eseguire questa azione dopo onSaveInstanceState

    Qui il codice nella scheda di pagina:

     public void removeAllfragments() { if ( mFragmentList != null ) { for ( Fragment fragment : mFragmentList ) { mFm.beginTransaction().remove(fragment).commit(); } mFragmentList.clear(); notifyDataSetChanged(); } } 

    Salvo solo la pagina corrente e ripristinato in onCreate() , dopo che i frammenti sono stati creati.

     if (savedInstanceState != null) mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) ); 

    Che cosa è che BasePagerAdapter ? È necessario utilizzare uno degli standard adattatori pager – FragmentPagerAdapter o FragmentStatePagerAdapter , a seconda che si desideri che i frammenti non siano più necessari per ViewPager per essere mantenuti in giro (il primo) o per salvare il loro stato (il secondo) e ri – creata se necessario.

    ViewPager puoi trovare il codice di esempio per l'utilizzo di ViewPager

    È vero che la gestione di frammenti in un pager di visualizzazione attraverso istanze di attività è un po 'complicata, perché il FragmentManager nel framework si prende cura di salvare lo stato e ripristinare i frammenti attivi che il pager ha fatto. Tutto ciò significa veramente che l'adattatore durante l'initialization ha bisogno di assicurarsi che si ricollega con qualsiasi frammento restaurato. Puoi guardare il codice per FragmentPagerAdapter o FragmentStatePagerAdapter per vedere come è stato fatto.

    Se qualcuno ha problemi con il FragmentStatePagerAdapter che non ripristina correttamente lo stato dei suoi frammenti … cioè nuovi frammenti vengono creati da FragmentStatePagerAdapter anziché restituirli dallo stato …

    Assicurarsi di call ViewPager.setOffscreenPageLimit() PRIMA di call ViewPager.setAdapeter(fragmentStatePagerAdapter)

    Dopo aver chiamato ViewPager.setOffscreenPageLimit() … il ViewPager esaminerà immediatamente la sua scheda e cercherà di get i suoi frammenti. Ciò potrebbe accadere prima che ViewPager abbia la possibilità di ripristinare i frammenti di saveInstanceState (creando così nuovi frammenti che non possono essere ri-inizializzati da SavedInstanceState perché sono nuovi).

    Per get i frammenti dopo la modifica dell'orientamento devi utilizzare il .getTag ().

      getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager) 

    Per un po 'di più ho scritto il mio ArrayList per il mio PageAdapter per get il frammento da viewPagerId e il FragmentClass in qualsiasi posizione:

     public class MyPageAdapter extends FragmentPagerAdapter implements Serializable { private final String logTAG = MyPageAdapter.class.getName() + "."; private ArrayList<MyPageBuilder> fragmentPages; public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) { super(fm); fragmentPages = fragments; } @Override public Fragment getItem(int position) { return this.fragmentPages.get(position).getFragment(); } @Override public CharSequence getPageTitle(int position) { return this.fragmentPages.get(position).getPageTitle(); } @Override public int getCount() { return this.fragmentPages.size(); } public int getItemPosition(Object object) { //benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden Log.d(logTAG, object.getClass().getName()); return POSITION_NONE; } public Fragment getFragment(int position) { return getItem(position); } public String getTag(int position, int viewPagerId) { //getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem()) return "android:switcher:" + viewPagerId + ":" + position; } public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) { return new MyPageBuilder(pageTitle, icon, selectedIcon, frag); } public static class MyPageBuilder { private Fragment fragment; public Fragment getFragment() { return fragment; } public void setFragment(Fragment fragment) { this.fragment = fragment; } private String pageTitle; public String getPageTitle() { return pageTitle; } public void setPageTitle(String pageTitle) { this.pageTitle = pageTitle; } private int icon; public int getIconUnselected() { return icon; } public void setIconUnselected(int iconUnselected) { this.icon = iconUnselected; } private int iconSelected; public int getIconSelected() { return iconSelected; } public void setIconSelected(int iconSelected) { this.iconSelected = iconSelected; } public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) { this.pageTitle = pageTitle; this.icon = icon; this.iconSelected = selectedIcon; this.fragment = frag; } } public static class MyPageArrayList extends ArrayList<MyPageBuilder> { private final String logTAG = MyPageArrayList.class.getName() + "."; public MyPageBuilder get(Class cls) { // Fragment über FragmentClass holen for (MyPageBuilder item : this) { if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) { return super.get(indexOf(item)); } } return null; } public String getTag(int viewPagerId, Class cls) { // Tag des Fragment unabhängig vom State zB nach bei Orientation change for (MyPageBuilder item : this) { if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) { return "android:switcher:" + viewPagerId + ":" + indexOf(item); } } return null; } } 

    Quindi, solo creare un MyPageArrayList con i frammenti:

      myFragPages = new MyPageAdapter.MyPageArrayList(); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_data_frag), R.drawable.ic_sd_storage_24dp, R.drawable.ic_sd_storage_selected_24dp, new WidgetDataFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_color_frag), R.drawable.ic_color_24dp, R.drawable.ic_color_selected_24dp, new WidgetColorFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_textsize_frag), R.drawable.ic_settings_widget_24dp, R.drawable.ic_settings_selected_24dp, new WidgetTextSizeFrag())); 

    e aggiungerli al viewPager:

      mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages); myViewPager.setAdapter(mAdapter); 

    dopo questo potete get dopo l'orientamento cambiare il frammento corretto utilizzando la sua class:

      WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager() .findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class)); 

    Ho trovato questa soluzione semplice ed elegante. Suppone che l'attività sia responsabile della creazione dei frammenti e l'adattatore li serve.

    Questo è il codice dell'adattatore (niente di strano qui, ad exception del fatto che mFragments è un elenco di frammenti gestiti dall'attività)

     class MyFragmentPagerAdapter extends FragmentStatePagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } @Override public CharSequence getPageTitle(int position) { TabFragment fragment = (TabFragment)mFragments.get(position); return fragment.getTitle(); } } 

    L'integer problema di questo thread sta ottenendo un riferimento dei frammenti "vecchi", quindi uso questo codice nell'attività Creazione onCreate.

      if (savedInstanceState!=null) { if (getSupportFragmentManager().getFragments()!=null) { for (Fragment fragment : getSupportFragmentManager().getFragments()) { mFragments.add(fragment); } } } 

    Naturalmente puoi anche aggiustare ulteriormente questo codice se necessario, ad esempio assicurandoti che i frammenti siano istanze di una particolare class.

    Inserisci:

      @SuppressLint("ValidFragment") 

    prima della tua class.

    non funziona per fare qualcosa di simile:

     @SuppressLint({ "ValidFragment", "HandlerLeak" }) 
    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.