ViewPager et fragments-Quelle est la bonne façon de stocker l'état de fragment?

Fragments semblent être très agréable pour la séparation de la logique D'UI dans certains modules. Mais avec ViewPager son cycle de vie est encore brumeux pour moi. Alors les pensées du gourou sont vraiment nécessaires!

Modifier

voir solution muette ci-dessous; -)

champ d'application

activité principale a un ViewPager avec des fragments. Ces fragments pourraient mettre en œuvre une logique un peu différente pour d'autres activités (sous-domaine), de sorte que la les données des fragments sont remplies via une interface de rappel à l'intérieur de l'activité. Et tout fonctionne bien sur le premier lancement, mais!...

problème

lorsque l'activité est recréée (par exemple lors d'un changement d'orientation), il en va de même pour les fragments ViewPager . Le code (vous trouverez ci-dessous) dit que chaque fois que l'activité est créée, j'essaie de créer un nouvel adaptateur de fragments ViewPager de la même façon que les fragments (peut-être que c'est le problème) mais FragmentManager a déjà tous ces fragments stockés quelque part (où?) et démarre le mécanisme de récréation pour ceux. Ainsi, le mécanisme de récréation appelle l'onAttach du" vieux " fragment, onCreateView,etc. avec mon interface de rappel, appelez pour initialiser les données via la méthode implémentée de L'activité. Mais cette méthode pointe vers le fragment nouvellement créé qui est créé via la méthode onCreate de L'activité.

Problème

peut-être que j'utilise de mauvais modèles mais même Android 3 Pro book n'a pas beaucoup à ce sujet. Alors, s'il vous plaît , donnez-moi un coup de poing et montrez-moi comment le faire de la bonne façon. Merci beaucoup!

Code

Activité 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;
}

Adaptateur

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
}

}

Fragment

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... */
}

Solution

la solution stupide est de sauver les fragments à l'intérieur onSaveInstanceState (de L'activité de l'hôte) avec putFragment et les obtenir à l'intérieur onCreate via getFragment. Mais j'ai toujours le sentiment étrange que les choses ne devraient pas marcher comme ça... Voir code ci-dessous:

    @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();
    ...
}
463
demandé sur Impredicative 2011-10-31 13:18:32
la source

10 ответов

quand le FragmentPagerAdapter ajoute un fragment au FragmentManager, il utilise une étiquette spéciale basée sur la position particulière que le fragment sera placé. FragmentPagerAdapter.getItem(int position) n'est appelée lorsqu'un fragment de cette position n'existe pas. Après la rotation, Android remarquera qu'il a déjà créé/enregistré un fragment pour cette position particulière et il essaie simplement de se reconnecter avec elle avec FragmentManager.findFragmentByTag() , au lieu d'en créer un nouveau. Tout cela est gratuit lorsque vous utilisez le FragmentPagerAdapter et c'est pourquoi il est habituel d'avoir votre code d'initialisation de fragment à l'intérieur de la méthode getItem(int) .

même si nous n'utilisions pas un FragmentPagerAdapter , ce n'est pas une bonne idée de créer un nouveau fragment à chaque fois dans Activity.onCreate(Bundle) . Comme vous l'avez remarqué, lorsqu'un fragment est ajouté à la FragmentManager, il sera recréé pour vous après la rotation et il n'est pas nécessaire de l'ajouter à nouveau. Le faire est une cause fréquente d'erreurs quand on travaille avec des fragments.

une approche habituelle quand on travaille avec des fragments est celle-ci:

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

    ...

}

lors de l'utilisation d'un FragmentPagerAdapter , Nous cédons la gestion des fragments à l'adaptateur, et nous n'avons pas à effectuer les étapes ci-dessus. Par défaut, il ne préchargera qu'un Fragment devant et derrière la position actuelle (bien qu'il ne les détruise que si vous utilisez FragmentStatePagerAdapter ). Ceci est contrôlé par ViewPager.setOffscreenPageLimit (int) . En raison de cette, les méthodes d'appel direct sur les fragments à l'extérieur de l'adaptateur ne sont pas garanties d'être valides, car ils peuvent même ne pas être vivants.

pour faire court sur une longue histoire, votre solution d'utiliser putFragment pour pouvoir obtenir une référence par la suite n'est pas si folle, et pas si différente de la façon normale d'utiliser des fragments de toute façon (ci-dessus). Il est difficile d'obtenir une référence sinon parce que le fragment est ajouté par l'adaptateur, et pas vous personnellement. Assurez-vous que le offscreenPageLimit est assez haut pour charger vos fragments désirés à tout moment, puisque vous comptez sur sa présence. Cela évite les capacités de chargement paresseuses du ViewPager, mais semble être ce que vous désirez pour votre application.

une autre approche consiste à surcharger FragmentPageAdapter.instantiateItem(View, int) et sauvegarder une référence au fragment retourné du super-appel avant de le retourner (il a la logique de trouver le fragment, s'il est déjà présent).

Pour une image plus complète, jetez un oeil à quelques-unes des sources de FragmentPagerAdapter (court) et ViewPager (long).

432
répondu antonyt 2013-03-28 21:32:41
la source

je veux offrir une solution qui s'étend sur antonyt 's wonderful answer et la mention de priorité FragmentPageAdapter.instantiateItem(View, int) pour sauvegarder les références à créé Fragments afin que vous puissiez travailler sur eux plus tard. Cela devrait aussi fonctionner avec FragmentStatePagerAdapter ; voir les notes pour plus de détails.


voici un exemple simple de la façon d'obtenir une référence à la Fragments retourné par FragmentPagerAdapter qui ne s'appuyer sur le tags interne sur le Fragments . La clé est de passer outre instantiateItem() et sauvegardez les références dans à la place de dans 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();
        }
    }
}

ou si vous préférez travailler avec des tags à la place de membre de la classe des variables/les références à la Fragments , vous pouvez aussi saisir le tags , établi par le FragmentPagerAdapter dans le même manière: NOTE: Ceci ne s'applique pas à FragmentStatePagerAdapter car il ne définit pas tags lors de la création de son 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;
}

notez que cette méthode ne repose pas sur l'imitation du tag interne défini par FragmentPagerAdapter et utilise plutôt APIs appropriés pour les extraire. De cette façon, même si le tag change dans les versions futures du SupportLibrary , vous serez toujours en sécurité.


Non. oubliez que selon la conception de votre Activity , le Fragments vous essayez de travailler sur Mai ou peut ne pas exister encore, donc vous devez en tenir compte en faisant null vérifications avant d'utiliser vos références.

aussi, si à la place vous travaillez avec FragmentStatePagerAdapter , alors vous ne voulez pas garder des références dures à votre Fragments parce que vous pourriez avoir beaucoup d'entre eux et des références dures seraient inutilement les garder dans la mémoire. À la place, sauvegardez les références Fragment dans les variables WeakReference au lieu des variables standard. Comme ceci:

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...
}
34
répondu Tony Chan 2017-05-23 15:26:33
la source

j'ai trouvé une autre solution relativement facile pour votre question.

comme vous pouvez le voir à partir du FragmentPagerAdapter code source , les fragments gérés par FragmentPagerAdapter stocker dans le FragmentManager sous l'étiquette générée en utilisant:

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

le viewId est le container.getId() , le container est votre instance ViewPager . Le index est la position du fragment. Par conséquent, vous pouvez économiser de l' objet id du 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);

Si vous souhaitez communiquer avec ce fragment, vous pouvez obtenir si de FragmentManager , tels que:

getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
16
répondu user2110066 2017-02-10 20:06:06
la source

je veux offrir une solution alternative pour peut-être un cas légèrement différent, puisque beaucoup de mes recherches de réponses ont continué à me conduire à ce fil.

Mon cas - Je crée / ajoute des pages de façon dynamique et les glisse dans un ViewPager, mais quand j'ai tourné (onConfigurationChange) je finis avec une nouvelle page parce que bien sûr OnCreate est appelé de nouveau. Mais je veux garder référence à toutes les pages qui ont été créées avant la rotation.

Problème - Je n'ai pas d'identificateurs uniques pour chaque fragment que je crée, donc la seule façon de faire référence était de stocker les références dans un tableau à restaurer après le changement de rotation/configuration.

solution de Contournement - Le concept clé était d'avoir L'activité (qui affiche les Fragments) aussi gérer le tableau de références aux Fragments existants, puisque cette activité peut utiliser Bottes en onssaveinstancestate

public class MainActivity extends FragmentActivity

dans le cadre de cette activité, je déclare un membre privé pour suivre les pages ouvertes

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

ceci est mis à jour chaque fois que l'onSaveInstanceState est appelé et restauré dans onCreate

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

... donc une fois stocké, il peut être récupéré...

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

ce sont les changements nécessaires à l'activité principale, et j'ai donc besoin de membres et méthodes dans mon FragmentPagerAdapter pour que cela fonctionne, donc dans

public class ViewPagerAdapter extends FragmentPagerAdapter

une construction identique (comme indiqué ci-dessus dans activité principale )

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

et cette synchronisation (comme utilisé ci-dessus dans onSaveInstanceState) est soutenue spécifiquement par les méthodes

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

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

et enfin, dans la classe de fragments

public class CustomFragment extends Fragment

pour que tout cela fonctionne, il y a eu deux changements, d'abord

public class CustomFragment extends Fragment implements Serializable

et en ajoutant ceci pour onCreate afin que les Fragments ne soient pas détruits

setRetainInstance(true);

je suis encore dans le processus d'envelopper ma tête autour des Fragments et le cycle de vie Androïde, donc attention ici est qu'il peut y avoir des redondances/inefficacités dans cette méthode. Mais cela fonctionne pour moi et j'espère que pourrait être utile pour d'autres avec des cas similaires au mien.

15
répondu Frank Yin 2012-12-04 08:12:19
la source

ma solution est très grossière mais fonctionne: étant mes fragments dynamiquement créés à partir de données conservées, je supprime tout simplement tous les fragments du PageAdapter avant d'appeler super.onSaveInstanceState() et puis les recréer sur la création d'activité:

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

vous ne pouvez pas les supprimer dans onDestroy() , sinon vous obtenez cette exception:

java.lang.IllegalStateException: ne peut pas effectuer cette action après onSaveInstanceState

ici le code dans la page adaptateur:

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

Je ne sauve la page courante et la restaure dans onCreate() , après que les fragments aient été créés.

if (savedInstanceState != null)
    mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) );  
8
répondu Sir John 2016-09-27 13:09:23
la source

Qu'est-ce que c'est que BasePagerAdapter ? Vous devez utiliser l'un des adaptateurs de pager standard -- soit FragmentPagerAdapter ou FragmentStatePagerAdapter , selon que vous voulez des Fragments qui ne sont plus nécessaires par le ViewPager pour être soit maintenu autour (le premier) ou avoir leur état sauvé (le dernier) et recréé si nécessaire à nouveau.

exemple de code pour l'utilisation de ViewPager peut être trouvé ici

il est vrai que la direction des fragments dans un pager de vue à travers les instances d'activité est un peu compliqué, parce que le FragmentManager dans le cadre prend soin de sauver l'état et de restaurer tous les fragments actifs que le pager a fait. Tout ce que cela signifie vraiment est que l'adaptateur lors de l'initialisation doit s'assurer qu'il se connecte de nouveau avec n'importe quels fragments restaurés il ya. Vous pouvez regarder le code pour FragmentPagerAdapter ou FragmentStatePagerAdapter pour voir comment c'est fait.

4
répondu hackbod 2017-02-10 20:08:35
la source

si quelqu'un a des problèmes avec leur FragmentStatePagerAdapter ne pas correctement restaurer l'état de ses fragments...c'est à dire...de nouveaux Fragments sont créés par le FragmentStatePagerAdapter au lieu de lui les restaurer de l'état...

n'oubliez pas d'appeler ViewPager.setOffscreenPageLimit() avant d'appeler ViewPager.setAdapeter(fragmentStatePagerAdapter)

sur appel ViewPager.setOffscreenPageLimit() ...le ViewPager immédiatement regarder à son adaptateur et essayer d'obtenir ses fragments. Cela pourrait se produire avant que le ViewPager ait une chance de restaurer les Fragments de savedInstanceState(créant ainsi de nouveaux Fragments qui ne peuvent pas être réinitialisés à partir de SavedInstanceState parce qu'ils sont nouveaux).

2
répondu dell116 2017-02-05 05:31:16
la source

j'ai trouvé cette solution simple et élégante. Il suppose que l'activité est responsable de la création de Fragments, et la Carte sert juste.

c'est le code de l'adaptateur (rien de bizarre ici, sauf que mFragments est une liste de fragments maintenus par L'activité)

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

tout le problème de ce fil est d'obtenir une référence des "vieux" fragments, donc j'utilise ce code dans L'activité onCreate.

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

bien sûr, vous pouvez affiner ce code si nécessaire, par exemple en vous assurant que les fragments sont des instances d'une classe particulière.

0
répondu Merlevede 2016-07-19 19:31:30
la source

Pour obtenir les fragments après changement d'orientation, vous devez utiliser le .getTag ().

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

pour un peu plus de manipulation j'ai écrit mon propre ArrayList pour mon PageAdapter pour obtenir le fragment par viewPagerId et FragmentClass à n'importe quelle Position:

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

il suffit donc de créer un MyPageArrayList avec les fragments:

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

et ajoutez-les au viewPager:

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

après ce vous pouvez obtenir après orientation changer le fragment correct en utilisant sa classe:

        WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
            .findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
0
répondu Scrounger 2017-01-29 02:47:26
la source

ajouter:

   @SuppressLint("ValidFragment")

avant votre classe.

il ne marche pas faire quelque chose comme ceci:

@SuppressLint({ "ValidFragment", "HandlerLeak" })
-28
répondu andro_stackoverflow 2015-12-17 23:58:07
la source