Могу ли я зарегистрировать MVP Presenter внутри фрагмента

Я следовал шаблону MVP, предоставленному Google для реорганизации моего приложения. У меня есть одна MainActivity и много фрагментов, и мне кажется, что создавать действия для каждого фрагмента не так уж и сложно, поэтому я подумал зарегистрировать докладчика во фрагменте. Я вижу, что каждый фрагмент регистрирует своего собственного докладчика, но я не уверен, насколько это неправильно... :)

Итак, вот мой ведущий:

public class FirstPresenter implements FirstContract.Presenter {
    private final FirstContract.View mView;

    public FirstPresenter(FirstContract.View view) {
        mView = view;
    }

    @Override
    public void start() {
        Log.e(TAG, "Start");
    }
}

И вот мой фрагмент:

public class FirstFragment extends Fragment implements FirstContract.View {
    private FirstContract.Presenter mPresenter;

@Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container
            , Bundle savedInstanceState) {
...
// I register firstFragment presenter here.
mPresenter = new FirstPresenter(this);
...

Итак, мой вопрос, это правильный путь? Могу ли я зарегистрировать Presenter в Fragment вместо этого в Activity? И если это не правильный путь, есть ли хороший пример для обработки MVP с одним действием и несколькими фрагментами?

Спасибо, ребята, БР!

Ответ 1

Как вы можете видеть в образцах Google https://github.com/googlesamples/android-architecture), Activities create Presenters. Кроме того, Views присоединяется к Activity и Presenters в качестве параметра для получения представлений (Fragments).

После выполнения Fragment транзакции или состояния Fragment (просмотра) восстановлено Presenters создается и принимает Fragments (views) как параметр, чем вызов

view.setPresenter(T presenter); 

методы просмотров и Presenters регистрируются для просмотра.

Я думаю, что создание Presenter в Fragment не является хорошей практикой. Прежде всего это отдельные слои. Это незаконно для Разделения проблем. Во-вторых, если вы создаете презентатор в Fragment, вы привязываете свою жизнь Presenter к просмотру LifeCycle, а когда Fragment уничтожается и воссоздается, вы создаете нового ведущего, но это разные слои.

Модель - это интерфейс, определяющий отображаемые данные или иным образом действующие в пользовательском интерфейсе.

Ведущий действует на модель и представление. Он извлекает данные из репозиториев (модели) и форматирует их для отображения в представлении.

Представление - это пассивный интерфейс, который отображает данные (модель) и маршрутизирует пользовательские команды (события) ведущему, чтобы воздействовать на эти данные.

Итак, Activity может действовать как overall controller, который создает Presenters и Views и связывает их.

введите описание изображения здесь

Если мы поговорим о вашем вопросе, да, вы можете зарегистрировать презентатор в фрагменте. Но вам следует избегать создания презентаторов в фрагментах, которые вы используете в качестве представления.

Но в Android-сообществе есть много разных подходов к шаблону MVP, как показано ниже. https://plus.google.com/communities/114285790907815804707

Почему действия не являются элементами ui? http://www.techyourchance.com/activities-android/

Ответ 2

Если вы используете одну единственную операцию для размещения нескольких фрагментов, а также используете Dagger 2 для инъекции нужного вам докладчика, вы можете напрямую внедрить каждого докладчика в каждый фрагмент.

Моя история использования

Я делаю проект с архитектурой через несколько месяцев, так как я узнал о Android Jetpack Navigation Component, я начал переносить все представления моего приложения в этот шаблон.

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

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

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

Дело в том, что если мне нужно иметь несколько фрагментов внутри одного хоста Activity, я должен создать экземпляр каждого докладчика и пропустить его через мой FragmentManager внутри каждого фрагмента, и я думаю, что это не то, на что я смотрел, поскольку он добавляет несколько экземпляров объекта. ведущий от Host Activity.

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

Один простой способ сделать это с несколькими фрагментами - просто не думать об активности хоста и вводить презентаторов внутри каждого фрагмента.

Делая это с Dagger, он делает инъекцию чище.

Взгляните на простой пример

class MainMenuActivity : BaseActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        inflateMainFragment(savedInstanceState)
    }

      override fun getLayout(): Int {
        return R.layout.activity_main_menu
    }

    fun inflateMainFragment(savedInstanceState: Bundle?){
        if (savedInstanceState == null) {
            val fragment = MainMenuFragment()
            supportFragmentManager
                .beginTransaction()
                .add(R.id.nav_host_fragment, fragment)
                .commit()
        }
    }
}

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

class MapsFragment: BaseMapFragment(), MapContract.MapView {

    private lateinit var mMap: GoogleMap

    @Inject
    lateinit var presenter: MapsPresenter

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_paseo,container,false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (requireActivity().application as YawpApplication).getAppComponent()?.inject(this)
        presenter.attachView(this)
        setupToolbar()
        setupMap()
    }
}

А используя жизненный цикл фрагментов, вы можете отсоединить все ваши представления фрагментов в onDestroyView(), а также сэкономить некоторое пространство памяти при запуске сборщика мусора.

 override fun onDestroyView() {
        super.onDestroyView()
        presenter.detachView()
        presenter.detachJob()
    }

На официальном репозитории Google я нашел вопрос, который помог мне понять его лучше.

Вы можете проверить это здесь