Android MVP - Как общаться между презентатором активности и презентатором фрагментов

У меня есть активность с тремя фрагментами, в настоящее время я использую ViewPager. Я хочу реализовать MVP и обмениваться данными между презентатором активности и презентаторами фрагментов. I:

  • Передача данных из презентатора активности в презентаторы фрагментов
  • Отправка события из презентаторов фрагментов в презентацию активности
  • ...

Но я не знаю, как это сделать по-официальному. Я могу использовать BusEvent, но я не думаю, что это хорошая практика.

Ответы

Ответ 1

Связь между фрагментами и деятельностью или наоборот может быть осуществлена с помощью ответа nnn, или вы можете использовать ViewModel и LiveData обеспечивают более чистый способ и уважают жизненный цикл от fragments и activities которые могут спасти от написания нескольких строк кода, пытаясь предотвратить невидимый fragment от получения данных на заднем плане.

Сначала вы расширяете класс ViewModel, инициализируете Livedata и некоторые вспомогательные методы.

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

}

Затем вы инициализируете ViewModel в своей деятельности.

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


}

}

чтение данных по фрагментам:

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

Чтобы изменить значения любых живых данных, вы можете использовать один из методов в любом из фрагментов или в упражнении:

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

Что происходит за кулисами:

когда вы используете mViewModel = ViewModelProviders.of(this).get(MyViewModel.class) вы создаете экземпляр ViewModel и привязывает его к жизненному циклу данного действия фрагмента, поэтому модель представления уничтожает только activity или fragement остановился. если вы используете mViewModel = ViewModelProviders.of(getActivity()). get (MyViewModel.class), you are bindig it to the lifecycle if the parent действие '

когда вы используете mViewModel.getToFragmentA().observe() или mViewModel.getToFragmentB().observe() или mViewModel.getToAllFragments().observe() вы подключаете LiveData в классе MyViewModel к данному фрагменту или операции со значением метод onChange() обновляется во всех классах, которые наблюдают за методом.

Для личного Livedata я рекомендую немного исследований о Livedata ViewModel которые можно найти на YouTube или по этой ссылке.

Ответ 2

В соответствии с моим пониманием, для вашего UseCase, предположим, что ActivityA имеет viewPager, имеющий 3 фрагмента (FragmentA, FragmentB, FragmentC).

ActivityA имеет ActivityPresenterA

FragmentA имеет FragmentPresenterA

В соответствии с MVP, FragmentPresenterA должен отвечать за все логические и бизнес-потоки только FragmentA и должен взаимодействовать только с FragmentA. Поэтому FragmentPresenterA не может напрямую взаимодействовать с ActivityPresenterA.

Для связи с Fragment to Activity презентатор не должен быть задействован, и это должно быть сделано, поскольку мы будем общаться в архитектуре, отличной от MVP, то есть с помощью интерфейса.

То же самое применяется для связи "Активность в Фрагмент".

Для связи между Activity и Fragment читайте здесь

Ответ 3

Вы можете использовать один докладчик для этого случая.

Используйте ваш Activity Presenter, чтобы получить все данные, которые нужны вашим фрагментам. затем создайте интерфейсный класс и внедрите его в свои фрагменты.

Например:

Создайте открытый интерфейс для вашего PageAFragment (этот интерфейс будет мостом ваших данных от активности к фрагменту). и используйте метод вашего интерфейса для обработки результата от вашего докладчика для просмотра.

Это пример класса интерфейса, который я создал для полученных данных. для параметра вы можете выбрать то, что вы хотите, это зависит от ваших потребностей, но для меня я выбираю модель.

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

В классе MainActivity проверьте экземпляр фрагмента, который прикреплен к вашей активности. поместите свой проверочный экземпляр после того, как вы передадите фрагмент.

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

}

Я предположил, что receiveDataFromPresenter - это полученный метод нашего просмотра и получения данных для докладчика.

А теперь мы передадим данные от докладчика в callbackReceivedData

В PageAFragment реализовать CallbackReceivedData и переопределить метод onDataReceived. Теперь вы можете передавать данные о деятельности в ваш фрагмент.

public class PageAFragment extends Fragment implements CallbackReceivedData{

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

    }

    @Override
    public void onDataReceived(YourModel model) {

    }
}

Примечание: альтернативным способом вы можете использовать Bundle и передавать данные с помощью setArguments.

Если вы хотите отправить событие из фрагмента в действие, вы можете следовать этой идее.

Создайте класс Interface и внедрите его в свой MainActivity и переопределите метод от интерфейса к вашей деятельности, для моего случая я делаю это примерно так.

Вот мой класс CallbackSendData.

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

Реализуйте интерфейс CallbackSendData с MainActivity и переопределите метод 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.
  }



}

И к вашему PageAFragment вам нужно использовать метод attach для приведения вашего интерфейса. Метод присоединения, вызываемый после того, как фрагмент связан с его активностью. Если вы хотите понять жизненный цикл фрагмента, просто нажмите на эту ссылку: 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();
        }
    }

}

И теперь вы можете использовать CallbackSendData для отправки данных из активности во фрагмент.

Примечание: намного проще, если вы используете Dependency Injection для вашего проекта, вы можете использовать библиотеку Dagger2.

Удачи.

Ответ 4

Для связи между Fragment и Activity (будь то между их докладчиками или их классами) вам необходим интерфейс, который реализует ваша деятельность (например, ShoppingInteractor).

Таким образом, вы можете вызывать ((ShoppingInteractor)getActivity()).doSomething() во фрагментах. Если вы хотите, чтобы докладчик вашей задачи справился с задачей, вам нужно вызвать докладчика в doSomething внутри действия.

Вы можете сделать то же самое с фрагментами с другим интерфейсом и вызвать интерактивный фрагмент внутри действия.

Вы даже можете использовать Presenter getPresenter() внутри этих интерфейсов, чтобы иметь доступ к реальному докладчику. (((ShoppingInteractor)getActivity()).getPresenter().sendData(data)). То же самое касается фрагментов.

Ответ 5

Динамические данные:

Вот пример использования rxjava2, dagger2 и moxy.

Обусловленность:

  • Докладчики не зависят от жизненного цикла представления
  • Один ведущий - один взгляд. Представления не разделяют докладчиков между собой, и один просмотр имеет только одного докладчика.

Решение аналогично EventBus, но вместо этого использует Subject с ограниченным временем жизни. Он находится в компоненте, который создается при запуске действия, и уничтожается при его выходе. И активность, и фрагменты имеют неявный доступ к ней, они могут изменять значение и реагировать на него по-своему.

Пример проекта: https://github.com/Anrimian/ViewPagerMvpExample

Статические данные:

Просто используйте аргументы во фрагменте и тому подобное.

Ответ 6

Если вы хотите использовать MVP, первым шагом является создание одного докладчика для каждого просмотра, я имею в виду, если у вас есть 3 фрагмента, то будет 3 докладчика. Я думаю, что это плохая идея создать одного докладчика для 4 просмотров (упражнение и 3 фрагмента).