web-dev-qa-db-fra.com

Objets de communication entre plusieurs fragments dans ViewPager

J'ai 5 fragments dans ViewPager utilisés pour remplir un objet métier avec plusieurs champs étape par étape, à chaque étape, certains de ces champs seront définis. J'ai lu de nombreux articles sur la communication entre fragments, mais je ne me sens pas à l'aise comme les autres le préfèrent. Après avoir réfléchi à COMMENT puis-je faire cela dans mon cas, je commence enfin à penser à utiliser un objet modèle singleton auquel tous les fragments peuvent facilement accéder à ses champs et les remplir en étapes spécifiques.

En tant que nouvel utilisateur d'Android, je souhaite que les experts parlent de l'utilisation de singleton au lieu de transmettre des données entre des fragments tels qu'une interface implémentée (il semble que ce soit si compliqué et difficile à maintenir). Tout conseil sera utile.

16
saber

Bien que l’approche singleton semble facile à mettre en œuvre et à comprendre, c’est la meilleure façon de réaliser ce dont vous avez besoin. Une des raisons est que votre objet modèle, ou comme vous l'appelez, objet métier, vit en dehors du contexte de votre activité, ce qui peut créer des bogues difficiles à trouver. Par exemple. dans le cas où plusieurs instances de votre classe d'activité sont créées par le système et que les deux gardent une référence à votre singleton. Voyez comment vous perdez la trace de vos objets?

Ce que je ferais c'est 

  1. Faites que mon objet modèle soit implémenté Parcelable vous le détesterez au début, mais une fois que vous vous y habituerez, il deviendra le meilleur ami de votre modèle.
  2. Étant donné que votre modèle est parcelable, vous pouvez désormais le transmettre facilement entre fragments, activités et même l'enregistrer dans les préférences partagées. Il est important de noter ici que lorsque vous passez votre parcelable entre un fragment ou une activité, c’est comme si vous passiez par valeur, c’est-à-dire chaque fois qu'une nouvelle instance est créée.
  3. Définissez l'argument de votre fragment ou, s'il est déjà instancié, obtenez les arguments et ajoutez votre modèle. voici un exemple: si un fragment n’est pas encore actif:

    Bundle args = new Bundle(); args.putParcable("businessObject", yourBusinessObjectThatIsParcable); yourFragment.setArguments(args);

    Sinon: yourFragment.getArguments().putParcelable("businessObject", yourBusinessObjectThatIsParcable);

  4. Dans votre fragment, peut-être dans la méthode onCreateView, obtenez votre objet modèle comme ceci: MyParcableObject mpo = (MyParcableObject)getArguments().getParcelable("businessObject") et utilisez-le pour définir les données de votre choix.

  5. Lorsque vous avez terminé de modifier votre objet lors d'un clic sur un bouton ou dans la méthode onPause, mettez à jour les arguments de votre fragment de la même manière, _getArguments().putParcelable("businessObject", mpo);

  6. dans votre dernière page ou dernier fragment, vous pouvez transmettre votre objet à votre activité, ici comment procéder 

Même si cela semble fastidieux, vous devez vous y habituer en tant que développeur Android. Vous obtenez beaucoup plus de contrôle lorsque votre modèle implémente parcelable

Une autre façon de faire ce dont vous avez besoin est/ Modèle de délégation mais il est principalement utilisé pour les rappels, même si vous pouvez également transmettre des objets.

6
Vilen

Je ne recommanderais pas un singleton global. Il y a deux principales raisons:

  1. Par définition, un singleton limite votre application à une seule instance de l'objet métier principal. Si vous (ou un concepteur ou le chef de votre chef) décidez de disposer de plusieurs de ces ViewPagers à la fois, vous devrez de toute façon modifier votre architecture.
  2. La "façon de penser d'Android" est de s'attendre à ce que votre utilisateur mette votre application en arrière-plan et utilise d'autres applications avant de revenir à votre application. Si le système décide de supprimer votre application en arrière-plan, votre objet de mémoire singleton sera détruit et votre utilisateur aura perdu toute sa progression. Le moyen correct pour enregistrer l’état d’Android consiste à conserver l’état dans une activité ou un fragment, à l’enregistrer de manière appropriée dans onSaveInstanceState() et à le restaurer dans onCreate().

Tous les fragments du ViewPager peuvent obtenir une référence à l'activité parent via un appel à getActivity(). Ou si votre ViewPager est dans un fragment, tous les fragments peuvent accéder au fragment parent via un appel à getParentFragment(). Vous pouvez ensuite transtyper le résultat dans la classe appropriée (ou mieux encore, l'interface) et effectuer des appels de méthode pour transmettre des données en arrière. Gardez une trace des données de votre entreprise dans l'activité/le fragment parent. De cette façon, vous n'avez pas besoin d'un singleton global

Par exemple,

public class MyParentFragment extends Fragment {

  private String mPageOneData;
  private int mPageTwoData;
  private List<Date> mPageThreeData;

  public void setPageOneData(String data) {
    mPageOneData = data;
  }

  ...
}

public class PageOneFragment extends Fragment {

  private void sendDataToParent(String data) {
    Fragment f = getParentFragment();
    if (f != null && f instanceof MyParentFragment) {
      MyParentFragment parent = (MyParentFragment) f;
      f.setPageOneData(data);
    }
  }

}
6
Jschools
  1. vous pouvez enregistrer vos données dans l'événement onSaveInstanceState () de l'activité au cas où votre processus passerait à l'arrière-plan. Vous pouvez restaurer vos données dans l'événement onCreate () en utilisant Bundle et getExtras ().

  2. vous pouvez sauvegarder vos données dans la classe d’application et les données seront toujours là au cas où votre processus passerait à l’arrière-plan.

je préfère la première option parce que vous ne voulez pas créer de désordre dans la classe d’application avec toutes les données provenant de différentes activités et fragments. J'espère pouvoir vous aider :)

2
ediBersh

Avez-vous acheté EventBus

Je ne suis pas sûr que ce soit la meilleure approche, surtout quand votre question est trop large, mais ce sera cool avec seulement 5 fragments.

J'espère que ça aide

1
murielK

Avant de choisir une option, n'oubliez pas que l'utilisateur peut naviguer ou ouvrir n'importe quelle autre application afin que vous perdiez vos données. 

Vous pouvez utiliser onSaveInstanceState mais il sera en quelque sorte difficile à maintenir (comme vous l'avez dit, vous êtes nouveau dans Android). Vous pouvez aller avec singleton en utilisant 

  • Base de données - Utilisez cette option lorsque vous souhaitez conserver plusieurs enregistrements mais que vous devez créer un getter/setter de base de données ou utiliser un ORM tel que RushOrm, etc.
  • SharefPreference (de préférence) - Si vous souhaitez utiliser des valeurs uniques.

Dans les deux cas, vous allez créer un objet singleton et accéder à ses propriétés dans vos fragments.

0
Haris Qureshi

Je suppose que dans votre activité principale, il y a une ViewPager, et FragmentOne sera l'un des fragments à l'intérieur du pageur de vue. Ici, MainActivity communique avec FragmentOne pour actualiser son adaptateur. L'espoir est clair.

Dans votre MainActivity, ajoutez cette interface:

public interface Updateable {
    public void update();
}

Implémentez cette interface dans un fragment qui doit être mis à jour et écrivez le code pour notifier l'adaptateur dans la méthode update:

public class FragmentOne extends Fragment implements MainActivity.Updateable {
    ...
    @Override
    public void update() {
        // YOUR CODE TO UPDATE HERE, FOR EXAMPLE, HERE I'M UPDATING THE ADAPTER
        if ( adapter != null ) {
            adapter.notifyDataSetChanged();
        } else {
            Log.d("LOG_TAG", "null");
        }
    }
    ...
}

Appelez la méthode update à partir de MainActivity lorsque le fragment est chargé en premier. Vous pouvez faire ceci en remplaçant la méthode getItemPosition dans votre PagerAdapter, comme ceci:

@Override
public int getItemPosition(Object object) {    
    if ( object != null && object instanceof FragmentOne ) {
        FragmentOne f = (FragmentOne) object;

        f.update();
    }
    return super.getItemPosition(object);
}

Enfin, vous devez appeler notifyDataSetChanged () de votre adaptateur viewPager. Cela forcera l'adaptateur de votre viewpager à appeler la méthode getItemPosition. 

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        int previousState;
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

            if (previousState == ViewPager.SCROLL_STATE_SETTLING && state == ViewPager.SCROLL_STATE_IDLE) {

                if ( viewPagerAdapter.getItem(viewpager.getCurrentItem()) instanceof Pictures ) {
                    Log.d("LOG_TAG", "New Position=" + viewpager.getCurrentItem());

                    viewPagerAdapter.notifyDataSetChanged();
                }

            }
            previousState = state;
        }
    });
0
Valentino S.