web-dev-qa-db-fra.com

Android MVP - Comment communiquer entre le présentateur d'activité et le présentateur de fragments

J'ai une activité avec 3 fragments, actuellement j'utilise ViewPager. Je veux implémenter MVP et communiquer entre le présentateur d'activité et les présentateurs de fragments, à savoir:

  • Transmission des données du présentateur d'activité aux présentateurs de fragments
  • Envoi de l'événement des présentateurs de fragments au présentateur d'activité
  • ...

Mais je ne sais pas comment le faire de manière officielle. Je peux utiliser BusEvent mais je ne pense pas que ce soit une bonne pratique.

27
Norutan

La communication entre les fragments et l'activité ou vice-versa peut être effectuée en utilisant réponse de nnn ou vous pouvez utiliser ViewModel et LiveData qui fournit un moyen plus propre et respecte le cycle de vie à partir de fragments et activities qui peuvent éviter d'écrire quelques lignes de code afin d'empêcher un fragment non visible de recevoir des données en arrière-plan.

D'abord, vous étendez la classe ViewModel, initialisez la Livedata et certaines méthodes d'assistance.

public class MyViewModel extends ViewModel {
private MutableLiveData<String> toFragmentA, toFragmentB;
private MutableLiveData<List<String>>  toAllFragments;

public MyViewModel() {
    toFragmentA = new MutableLiveData<>();
    toFragmentB = new MutableLiveData<>();
    toAllFragments = new MutableLiveData<>();
}

public void changeFragmentAData(String value){
    toFragmentA.postValue(value);
}
public void changeFragmentBData(String value){
    toFragmentB.postValue(value);
}
public void changeFragmentAllData(List<String> value){
    toAllFragments.postValue(value);
}

public LiveData<String> getToFragmentA() {
    return toFragmentA;
}

public LiveData<List<String>> getToAllFragments() {
    return toAllFragments;
}

public LiveData<String> getToFragmentB() {
    return toFragmentB;
}

}

Ensuite, vous initialisez le ViewModel sur votre activité.

public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
private TabLayout tabLayout;
MyViewModel mViewModel;

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

    mViewModel = ViewModelProviders.of(this)
            .get(MyViewModel.class);

    viewPager.setAdapter(new Adapter(getSupportFragmentManager()));


}

}

lire les données dans les fragments:

 @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

    mViewModel.getToAllFragments().observe(this, new Observer<List<String>>() {
        @Override
        public void onChanged(List<String> s) {
            myList.addAll(s);
            //do something like update a RecyclerView
        }
    });

    mViewModel.getToFragmentA().observe(this, new Observer<String>() {


        @Override
        public void onChanged(String s) {
            mytext = s;
            //do something like update a TextView
        }
    });
}

pour modifier les valeurs de l'une des données en direct, vous pouvez utiliser l'une des méthodes dans l'un des fragments ou dans l'activité:

changeFragmentAData();
changeFragmentBData();
changeFragmentAllData();

Qu'est-ce qui se passe dans les coulisses:

lorsque vous utilisez mViewModel = ViewModelProviders.of(this).get(MyViewModel.class) vous créez une instance de ViewModel et la liez au cycle de vie de l'activité donnée du fragment de sorte que le modèle de vue est destroid uniquement le activity ou fragement est arrêté. si vous utilisez mViewModel = ViewModelProviders.of (getActivity ()). get (MyViewModel.class) you are bindig it to the lifecycle if the parent activity`

lorsque vous utilisez mViewModel.getToFragmentA().observe() ou mViewModel.getToFragmentB().observe() ou mViewModel.getToAllFragments().observe() vous connectez la classe LiveData in MyViewModel au fragment ou à l'activité donnée et la valeur de la méthode onChange() est mise à jour dans toutes les classes qui observent la méthode.

Je recommande par expérience personnelle un peu de recherche sur Livedata end ViewModel que vous pouvez sur youtube ou ce lien

3
sutuioncode

Selon ma compréhension, pour votre UseCase, supposons que ActivityA ait un viewPager ayant 3 Fragments (FragmentA, FragmentB, FragmentC).

ActivityA have ActivityPresenterA

FragmentA have FragmentPresenterA

Selon MVP, FragmentPresenterA devrait être responsable de tous les flux logiques et commerciaux de FragmentA uniquement et devrait communiquer avec FragmentA uniquement. Par conséquent, FragmentPresenterA ne peut pas communiquer directement avec ActivityPresenterA.

Pour la communication de Fragment à Activity, le présentateur ne devrait pas être impliqué et cela devrait être fait comme nous communiquerions dans une architecture non MVP, c'est-à-dire à l'aide de l'interface.

Il en va de même pour la communication de l'activité au fragment.

Pour la communication entre l'activité et le fragment, lisez ici

1
nnn

Vous pouvez utiliser un présentateur pour ce cas.

Utilisez votre présentateur d'activité pour obtenir toutes les données dont vos fragments ont besoin. puis créez une classe d'interface et implémentez-la dans vos fragments.

Par exemple:

Créez une interface publique pour votre PageAFragment (cette interface fera le pont de vos données de l'activité au fragment). et utilisez la méthode de votre interface pour gérer le résultat de votre présentateur à afficher.

Voici l'exemple de classe d'interface que j'ai créé pour les données reçues. Pour le paramètre, vous pouvez choisir ce que vous voulez, cela dépend de vos besoins, mais pour moi, je choisis le modèle.

public interface CallbackReceivedData {
    void onDataReceived(YourModel model);
}

Dans MainActivity Class , vérifiez l'instance de fragment qui s'est attachée à votre activité. placez votre instance de vérification après avoir validé le fragment.

public class MainActivity extends AppCompatActivity{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      //after commit the fragment
    if (fragment instanceof PageAFragment){
            callbackReceivedData = (CallbackReceivedData)fragment;
    }

  }
  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }

}

J'ai supposé que le receivedDataFromPresenter est la méthode reçue de notre vue et obtenir des données au présentateur.

Et maintenant, nous allons passer les données du présentateur à callbackReceivedData

Dans PageAFragment implémentez le CallbackReceivedData et remplacez le méthode onDataReceived . Vous pouvez maintenant transmettre les données de l'activité à votre fragment.

public class PageAFragment extends Fragment implements CallbackReceivedData{

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Override
    public void onDataReceived(YourModel model) {

    }
}

Remarque: Vous pouvez également utiliser Bundle et transmettre les données à l'aide de setArguments.

Si vous souhaitez envoyer un événement du fragment à l'activité , vous pouvez suivre cette idée.

Créez une classe Interface et implémentez-la dans votre MainActivity et remplacez la méthode de l'interface à votre activité, pour mon cas, je le fais quelque chose comme ça.

Voici ma classe CallbackSendData .

public interface CallbackSendData {
    void sendDataEvent(String event);
}

Implémentez l'interface CallbackSendData à votre MainActivity et remplacez le méthode sendDataEvent .

public class MainActivity extends AppCompatActivity implements CallbackSendData{

  private CallbackReceivedData callbackReceivedData;

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

     //after commit the fragment
     if (fragment instanceof PageAFragment){
         callbackReceivedData = (CallbackReceivedData)fragment;
     }

  }

  //this is the example method of MainActivity Presenter, 
  //Imagine it, as your view method.
  public void receivedDataFromPresenter(YourModel model){
      callbackReceivedData.onDataReceived(model);
  }    


  @Override
  public void sendDataEvent(String event){
     //You can now send the data to your presenter here.
  }



}

Et à votre PageAFragment , vous devez utiliser la méthode attach pour convertir votre interface. La méthode attach est appelée une fois que le fragment est associé à son activité. Si vous voulez comprendre le cycle de vie d'un fragment, cliquez simplement sur ce lien: https://developer.Android.com/reference/Android/app/Fragment.html .

public class PageAFragment extends Fragment implements CallbackReceivedData{

    private CallbackSendData callbackSendData;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }

    @Override
    public void onDataReceived(YourModel model) {
        //Received the data from Activity to Fragment here.
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup 
    container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.PagerAFragment, container, 
    false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle 
    savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Button Eventbutton;

        Eventbutton = view.findViewById(R.id.event_button);
        Eventbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                callbackSendData.sendDataEvent("send Data sample");
            }
        });
    }

   @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            callbackSendData = (CallbackSendData) context;
        }catch (ClassCastException e){
            e.printStackTrace();
        }
    }

}

Et maintenant, vous pouvez utiliser le CallbackSendData pour envoyer les données de l'activité au fragment.

Remarque: C'est beaucoup plus facile si vous utilisez l'injection de dépendances dans votre projet, vous pouvez utiliser la bibliothèque Dagger2.

Bonne chance.

0
Benidict Dulce

Pour communiquer entre un Fragment et un Activity (que ce soit entre leurs présentateurs ou leurs classes), vous avez besoin d'une interface que votre activité implémente (comme ShoppingInteractor).

De cette façon, vous pouvez appeler ((ShoppingInteractor)getActivity()).doSomething() Dans les fragments. Si vous souhaitez que le présentateur de votre activité gère la tâche, vous devez appeler le présentateur dans le doSomething à l'intérieur de l'activité.

Vous pouvez faire de même avec les fragments avec une autre interface et appeler l'interacteur du fragment à l'intérieur de l'activité.

Vous pouvez même avoir une Presenter getPresenter() à l'intérieur de ces interfaces pour avoir accès au présentateur réel. (((ShoppingInteractor)getActivity()).getPresenter().sendData(data)). Il en va de même pour les fragments.

0
Adib Faramarzi

Données dynamiques:

Voici un exemple utilisant rxjava2, dagger2 et moxy.

Conditionnalités:

  • Les présentateurs ne dépendent pas du cycle de vie de la vue
  • Un présentateur - une vue. Les vues ne partagent pas les présentateurs entre elles et une vue n'a qu'un seul présentateur.

La solution est similaire à l'EventBus, mais utilise à la place Subject avec une durée de vie limitée. C'est dans le composant qui est créé au début de l'activité et qui est détruit à la fin. L'activité et les fragments y ont un accès implicite, ils peuvent changer la valeur et y répondre à leur manière.

Exemple de projet: https://github.com/Anrimian/ViewPagerMvpExample

Données statiques:

Utilisez simplement des arguments dans le fragment et c'est tout.

0
Anrimian

Si vous souhaitez utiliser MVP, la première étape consiste à créer un présentateur pour chaque vue, je veux dire, si vous avez 3 fragments, alors il y aurait 3 présentateurs. Je pense que c'est une mauvaise idée de créer un présentateur pour 4 vues (activité et 3 fragments).

0
Victor