web-dev-qa-db-fra.com

Communiquer entre un fragment et une activité - meilleures pratiques

Cette question vise principalement à solliciter des opinions sur la meilleure façon de gérer mon application. J'ai trois fragments traités par une activité. Le fragment A a un élément cliquable sur la photo et le fragment B a 4 éléments cliquables les boutons. L'autre fragment affiche uniquement les détails lorsque l'utilisateur clique sur la photo. J'utilise ActionBarSherlock. 

Screen shot

Les boutons avant et arrière doivent modifier la photo pour la pose suivante ou précédente, respectivement. Je pouvais conserver la photo et les boutons dans le même fragment, mais je voulais les garder séparés au cas où je voudrais les réorganiser dans une tablette. 

J'ai besoin de conseils - devrais-je combiner les fragments A et B? Sinon, je devrai comprendre comment implémenter une interface pour 3 éléments cliquables. 

J'ai envisagé d'utiliser Roboguice, mais je suis déjà en train d'utiliser SherlockFragmentActivity, c'est donc un non-droit. J'ai vu la mention d'Otto, mais je n'ai pas vu de bons tutoriels sur la façon d'inclure dans un projet. Selon vous, quelle devrait être la meilleure pratique de conception? 

J'ai aussi besoin d'aide pour savoir comment communiquer entre un fragment et une activité. J'aimerais garder certaines données "globales" dans l'application, comme l'identifiant de pose. Existe-t-il un exemple de code que je peux voir en plus des informations de base du développeur Android? Ce n'est pas si utile. 

BTW, je stocke déjà toutes les informations sur chaque pose dans une base de données SQLite. C'est la partie facile. 

49
Kristy Welsh

Le moyen le plus simple de communiquer entre votre activité et vos fragments consiste à utiliser des interfaces. L'idée est essentiellement de définir une interface à l'intérieur d'un fragment A donné et de laisser l'activité implémenter cette interface.

Une fois cette interface implémentée, vous pouvez faire ce que vous voulez dans la méthode qu’elle remplace.

L’autre partie importante de l’interface est que vous devez appeler la méthode abstraite à partir de votre fragment et vous rappeler de l’intégrer à votre activité. Il devrait attraper un ClassCastException s'il n'est pas fait correctement.

Il y a un bon tutoriel sur Simple Developer Blog sur comment faire exactement ce genre de chose.

J'espère que cela vous a été utile!

70
Eenvincible

La méthode suggérée pour la communication entre fragments consiste à utiliser des callbacks\écouteurs gérés par votre activité principale.

Je pense que le code sur cette page est assez clair: http://developer.Android.com/training/basics/fragments/communicating.html

Vous pouvez également faire référence à l'application IO 2012 Schedule, conçue pour être une application de référence de facto. Vous pouvez le trouver ici: http://code.google.com/p/iosched/

En outre, voici une question SO avec une bonne information: Comment passer des données entre fragments

23
Booger

Il est implémenté par une interface de rappel: Tout d’abord, nous devons créer une interface:

public interface UpdateFrag {
     public void updatefrag();
    }

En activité faites le code suivant:

UpdateFrag updatfrag ;
public void updateApi(UpdateFrag listener) {
        updatfrag = listener;
   }

de l'événement à partir duquel le rappel doit être déclenché en activité:

updatfrag.updatefrag();

Dans Fragment, implémentez l'interface dans CreateView en utilisant le code suivant:

 ((Home)getActivity()).updateApi(new UpdateFrag() {
                @Override
                public void updatefrag() {
                   .....your stuff......
                }
            });
9
Jyoti

J'ai créé une bibliothèque d'annotations pouvant effectuer le casting à votre place. vérifier cela . https://github.com/zeroarst/callbackfragment/

@CallbackFragment
public class MyFragment extends Fragment {

    @Callback
    interface FragmentCallback {
       void onClickButton(MyFragment fragment);
    }    
    private FragmentCallback mCallback;

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt1
                mCallback.onClickButton(this);
                break;
            case R.id.bt2
                // Because we give mandatory = false so this might be null if not implemented by the Host.
                if (mCallbackNotForce != null)
                mCallbackNotForce.onClickButton(this);
                break;
        }
    }
}

Il génère ensuite une sous-classe de votre fragment. Et ajoutez-le simplement à FragmentManager.

public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().beginTransaction()
            .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
            .commit();
    }

    Toast mToast;

    @Override
    public void onClickButton(MyFragment fragment) {
        if (mToast != null)
            mToast.cancel();
        mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
        mToast.show();
    }
}
4
Arst

Il existe plusieurs façons de communiquer entre activités, fragments, services, etc. L’essentiel est de communiquer en utilisant des interfaces. Cependant, ce n'est pas un moyen productif de communiquer. Vous devez implémenter les auditeurs, etc.

Ma suggestion est d'utiliser un bus d'événement. Le bus d'événements est une implémentation de modèle de publication/abonnement.

Vous pouvez vous abonner à des événements de votre activité, puis publier ces événements dans vos fragments, etc.

Ici sur mon article de blog vous pouvez trouver plus de détails sur ce modèle et aussi un exemple de projet pour montrer l'utilisation.

2
Gunhan

Je ne suis pas sûr d'avoir bien compris ce que vous voulez faire, mais la méthode suggérée pour communiquer entre fragments est d'utiliser des rappels avec l'activité, jamais directement entre fragments. Voir ici http://developer.Android.com/training/basics/fragments/communicating.html

1
alex

Pour communiquer entre Activity et Fragments, il existe plusieurs options, mais après de nombreuses lectures et de nombreuses expériences, j'ai découvert que cela pouvait être repris de la manière suivante:

  • Activity veut communiquer avec l'enfant Fragment => Écrivez simplement des méthodes publiques dans votre classe Fragment et laissez le Activity les appeler
  • Fragment veut communiquer avec le parent Activity => Cela nécessite un peu plus de travail, comme le lien officiel Android https://developer.Android.com/training/basics/fragments/communicating suggère, ce serait un excellente idée de définir une interface qui sera implémentée par la Activity et qui établira un contrat pour toute Activity qui souhaite communiquer avec cette Fragment. Par exemple, si vous avez FragmentA, qui veut communiquer avec tout activity qui l’inclut, définissez ensuite FragmentAInterface qui définira la méthode que la FragmentA peut appeler pour le activities qui décide de l’utiliser.
  • Une Fragment veut communiquer avec une autre Fragment => C'est le cas où vous obtenez la situation la plus «compliquée». Puisque vous pourriez potentiellement avoir besoin de transmettre des données de FragmentA à FragmentB et vice versa, cela pourrait nous amener à définir 2 interfaces, FragmentAInterface qui sera implémentée par FragmentB et FragmentAInterface qui sera implémentée par FragmentA. Cela va commencer à rendre les choses en désordre. Et imaginez si vous avez un peu plus de Fragments sur place, et même le parent activity souhaite communiquer avec eux. Eh bien, cette affaire est le moment idéal pour établir une ViewModel partagée pour la activity et c'est fragments. Plus d'infos ici https://developer.Android.com/topic/libraries/architecture/viewmodel . En gros, vous devez définir une classe SharedViewModel, qui contient toutes les données que vous voulez partager entre activity et fragments et qui auront besoin de communiquer des données entre elles.

Le cas ViewModel rend les choses plus simples à la fin, car vous n'avez pas à ajouter de logique supplémentaire qui rend les choses sales dans le code et désordonnées. De plus, cela vous permettra de séparer la collecte (via des appels vers une base de données SQLite ou une API) des données de la variable Controller (activities et fragments).

Vous pouvez créer déclarer une interface publique avec une déclaration de fonction dans le fragment et implémenter l'interface dans l'activité. Ensuite, vous pouvez appeler la fonction à partir du fragment. 

0
Jacob Abraham

J'utilise Intents pour communiquer des actions à l'activité principale. L’activité principale consiste à les écouter en remplaçant NewIntent (Intention Intention). L'activité principale traduit ces actions en fragments correspondants, par exemple.

Donc, vous pouvez faire quelque chose comme ça:

public class MainActivity extends Activity  {

    public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
    public static final String INTENT_ACTION_SHOW_BAR = "show_bar";


   @Override
   protected void onNewIntent(Intent intent) {
        routeIntent(intent);
   }

  private void routeIntent(Intent intent) {
       String action = intent.getAction();
       if (action != null) {               
            switch (action) {
            case INTENT_ACTION_SHOW_FOO:
                // for example show the corresponding fragment
                loadFragment(FooFragment);
                break;
            case INTENT_ACTION_SHOW_BAR:
                loadFragment(BarFragment);
                break;               
        }
    }
}

Puis à l'intérieur de n'importe quel fragment pour montrer le fragment foo:

Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
0
Pepster