risposta-alla-domanda-sullo-sviluppo-web-bd.com

ViewPager e frammenti: qual è il modo giusto per archiviare lo stato di un frammento?

I frammenti sembrano essere molto piacevoli per la separazione della logica dell'interfaccia utente in alcuni moduli. Ma insieme a ViewPager il suo ciclo di vita è ancora nebbioso. Quindi i pensieri del Guru sono assolutamente necessari!

Modificare

Guarda la soluzione stupida qui sotto ;-)

Scopo

L'attività principale ha un ViewPager con frammenti. Questi frammenti potrebbero implementare una logica un po 'diversa per altre attività (sottomeniche), quindi i dati dei frammenti vengono riempiti tramite un'interfaccia di callback all'interno dell'attività. E tutto funziona bene al primo avvio, ma! ...

Problema

Quando l'attività viene ricreata (ad esempio sul cambiamento di orientamento), anche i frammenti ViewPager. Il codice (che troverete di seguito) dice che ogni volta che l'attività viene creata cerco di creare un nuovo adattatore ViewPager frammenti uguale ai frammenti (forse questo è il problema) ma FragmentManager ha già tutti questi frammenti memorizzati da qualche parte (dove?) e avvia il meccanismo di ricreazione per quelli. Pertanto, il meccanismo di ricreazione richiama il "vecchio" frammento su Attach, onCreateView, ecc. Con la mia chiamata all'interfaccia di richiamata per l'avvio di dati tramite il metodo implementato di Activity. Ma questo metodo punta al frammento appena creato che viene creato tramite il metodo onCreate di Activity.

Problema

Forse sto usando schemi sbagliati ma anche il libro di Android 3 Pro non ne ha molto. Quindi, per favore , dammi un paio di punch e indica 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 stupida è salvare i frammenti all'interno di onSaveInstanceState (di Attività host) con putFragment e scaricarli su onCreate tramite getFragment. Ma ho ancora la strana sensazione che le cose non dovrebbero funzionare così ... Vedi il 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();
    ...
}
476

Quando FragmentPagerAdapter aggiunge un frammento a FragmentManager, utilizza un tag speciale in base alla posizione particolare in cui verrà inserito il frammento. FragmentPagerAdapter.getItem(int position) viene chiamato solo quando non esiste un frammento per quella posizione. Dopo la rotazione, Android noterà che ha già creato/salvato un frammento per questa particolare posizione e quindi cerca semplicemente di riconnettersi con essa con FragmentManager.findFragmentByTag(), invece di crearne uno nuovo. Tutto questo è gratuito quando si utilizza FragmentPagerAdapter ed è il motivo per cui è normale avere il codice di inizializzazione del frammento all'interno del metodo getItem(int).

Anche se non usassimo un FragmentPagerAdapter, non è una buona idea creare un nuovo frammento ogni volta in Activity.onCreate(Bundle). Come avrai notato, quando un frammento viene aggiunto a FragmentManager, verrà ricreato per te dopo la rotazione e non è necessario aggiungerlo di nuovo. Farlo è 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, abbandoniamo la gestione dei frammenti per l'adattatore e non è necessario eseguire i passaggi precedenti. Di default, precaricherà solo un Frammento davanti e dietro la posizione corrente (sebbene non li distrugga a meno che tu non stia usando FragmentStatePagerAdapter). Questo è controllato da ViewPager.setOffscreenPageLimit (int) . Per questo motivo, non è garantito che i metodi di chiamata diretta sui frammenti esterni all'adattatore siano validi, perché potrebbero non essere nemmeno vivi.

Per farla breve, la soluzione per usare putFragment per poter ottenere un riferimento in seguito non è così folle, e non è così diversa dal solito modo di usare i frammenti comunque (sopra). È difficile ottenere un riferimento altrimenti, poiché il frammento viene aggiunto dall'adattatore e non tu personalmente. Assicurati che offscreenPageLimit sia abbastanza alto da caricare i frammenti desiderati in ogni momento, dal momento che ti affidi alla presenza. Ciò ignora 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 super chiamata prima di restituirlo (ha la logica per trovare il frammento, se già presente).

Per un'immagine più completa, date un'occhiata ad alcuni dei sorgenti di FragmentPagerAdapter (breve) e ViewPager (lungo).

441
antonyt

Voglio offrire una soluzione che si espande in antonyt 's meravigliosa risposta e menzione di override FragmentPageAdapter.instantiateItem(View, int) per salvare i riferimenti creare Fragments in modo da poter lavorare su di essi in seguito. Questo dovrebbe funzionare anche con FragmentStatePagerAdapter; vedere le note per i dettagli.


Ecco un semplice esempio di come ottenere un riferimento al Fragments restituito da FragmentPagerAdapter che non si basa sul tags interno impostato su Fragments. La chiave è sovrascrivere instantiateItem() e salvare i riferimenti in là 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 (i.e. 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 preferisci lavorare con tags invece di variabili membro membro/riferimenti a Fragments puoi anche prendere il tags impostato da FragmentPagerAdapter nello stesso modo: NOTA: questo non si applica a FragmentStatePagerAdapter poiché non imposta tags durante la creazione di 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;
}

Si noti che questo metodo NON si basa sul mimare il tag interno impostato da FragmentPagerAdapter e utilizza invece API appropriate per recuperarli. In questo modo, anche se il tag cambia nelle future versioni di SupportLibrary, sarai comunque al sicuro.


Non dimenticare che a seconda del design del tuo Activity, il Fragments in cui stai cercando di funzionare potrebbe o potrebbe non esistere ancora, quindi devi tener conto di ciò facendo null controlla prima di utilizzare i tuoi riferimenti.

Inoltre, se invece stai lavorando con FragmentStatePagerAdapter, allora non vuoi mantenere dei riferimenti duri al tuo Fragments perché potresti averne molti e riferimenti duri li terrebbero inutilmente in memoria. Salvate invece i riferimenti Fragment nelle variabili WeakReference invece di quelli 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...
}
35
Tony Chan

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

Come puoi vedere dal codice sorgente di FragmentPagerAdapter , i frammenti gestiti da FragmentPagerAdapter memorizzano nel FragmentManager sotto il tag generato usando:

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

viewId è container.getId(), container è l'istanza ViewPager. index è la posizione del frammento. Quindi è possibile salvare l'ID oggetto su 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 vuoi comunicare con questo frammento, puoi ottenere se da FragmentManager, come ad esempio:

getSupportFragmentManager().findFragmentByTag("Android:switcher:" + viewpagerid + ":0")
18
user2110066

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

Il mio caso - Sto creando/aggiungendo pagine dinamicamente e facendole scorrere in un ViewPager, ma quando ruotato (onConfigurationChange) finisco con una nuova pagina perché Ovviamente OnCreate viene chiamato di nuovo. Ma voglio mantenere il riferimento a tutte le pagine che sono state create prima della rotazione.

Problema - Non ho identificatori univoci per ogni frammento che creo, quindi l'unico modo per fare riferimento è stato in qualche modo memorizzare i riferimenti in una matrice da ripristinare dopo il cambio di rotazione/configurazione.

Soluzione alternativa - Il concetto chiave era che l'attività (che visualizza i frammenti) gestisse anche la serie 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 per tenere traccia delle pagine aperte

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

Questo viene aggiornato ogni 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);
}

Questi erano i cambiamenti necessari per l'attività principale, e quindi avevo bisogno dei membri e dei metodi all'interno del mio FragmentPagerAdapter affinché questo funzionasse, quindi all'interno

public class ViewPagerAdapter extends FragmentPagerAdapter

un costrutto identico (come mostrato sopra in MainActivity)

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

e questa sincronizzazione (come usata sopra in onSaveInstanceState) è supportata specificamente dai metodi

public List<Fragment> exportList() {
    return _pages;
}

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

E poi finalmente, nella classe dei frammenti

public class CustomFragment extends Fragment

per far funzionare tutto questo, c'erano due cambiamenti, in primo luogo

public class CustomFragment extends Fragment implements Serializable

e quindi aggiungendo questo a onCreate in modo che Frammenti non vengano distrutti

setRetainInstance(true);

Sono ancora in procinto di avvolgere la mia mente su Frammenti e sul ciclo di vita di Android, quindi l'avvertenza qui potrebbe esserci ridondanze/inefficienze in questo metodo. Ma funziona per me e spero possa essere utile per gli altri con casi simili ai miei.

16
Frank Yin

La mia soluzione è molto scortese ma funziona: essendo i miei frammenti creati dinamicamente da dati conservati, rimuovo semplicemente tutti i frammenti dalla PageAdapter prima di chiamare super.onSaveInstanceState() e quindi li ricreamo nella creazione di attività:

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

Non puoi rimuoverli in onDestroy(), altrimenti ottieni questa eccezione:

Java.lang.IllegalStateException: Impossibile eseguire questa azione dopo onSaveInstanceState

Qui il codice nell'adattatore di pagina:

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

Io salvo solo la pagina corrente e la ripristino in onCreate(), dopo che i frammenti sono stati creati.

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

Cos'è BasePagerAdapter? Si dovrebbe usare uno degli adattatori standard del cercapersone - sia FragmentPagerAdapter o FragmentStatePagerAdapter, a seconda se si desidera che Frammenti non più necessari da ViewPager siano mantenuti in giro (il primo) o che il loro stato sia salvato (il secondo) e re -creato se necessario di nuovo.

È possibile trovare il codice di esempio per l'utilizzo di ViewPagerqui

È vero che la gestione dei frammenti in un visualizzatore di pagine attraverso istanze di attività è un po 'complicata, poiché il FragmentManager nel framework si occupa di salvare lo stato e ripristinare eventuali frammenti attivi creati dal cercapersone. Tutto ciò significa in realtà che l'adattatore durante l'inizializzazione deve essere sicuro che si ricolleghi con qualsiasi frammento ripristinato. Puoi vedere il codice per FragmentPagerAdapter o FragmentStatePagerAdapter per vedere come è fatto.

4
hackbod

Se qualcuno sta avendo problemi con il loro FragmentStatePagerAdapter non ripristina correttamente lo stato dei suoi frammenti ... cioè ... nuovi frammenti vengono creati dal FragmentStatePagerAdapter invece di ripristinarli dallo stato ...

Assicurati di chiamare ViewPager.setOffscreenPageLimit() PRIMA di chiamare ViewPager.setAdapeter(fragmentStatePagerAdapter)

Dopo aver chiamato ViewPager.setOffscreenPageLimit()... il ViewPager immediatamente guarda il suo adattatore e prova a recuperare i suoi frammenti. Questo potrebbe accadere prima che il ViewPager abbia la possibilità di ripristinare i Fragments da savedInstanceState (creando così nuovi Fragments che non possono essere reinizializzati da SavedInstanceState perché sono nuovi).

2
dell116

Ho trovato questa soluzione semplice ed elegante. Presume che l'attività è responsabile della creazione dei frammenti e l'adattatore li serve solo loro.

Questo è il codice dell'adattatore (niente di strano qui, eccetto il fatto che mFragments è una lista di frammenti mantenuti 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'intero problema di questo thread è ottenere un riferimento dei "vecchi" frammenti, quindi utilizzo questo codice nel onCreate di Activity.

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

Naturalmente è possibile perfezionare ulteriormente questo codice se necessario, ad esempio assicurandosi che i frammenti siano istanze di una particolare classe.

0
Merlevede

Per ottenere i frammenti dopo aver cambiato l'orientamento devi usare il .getTag ().

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

Per un po 'più di gestione ho scritto il mio ArrayList per il mio PageAdapter per ottenere il frammento di viewPagerId e 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 z.B. 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 basta 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 aggiungili a viewPager:

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

dopo questo puoi ottenere dopo l'orientamento cambiare il frammento corretto usando la sua classe:

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