Могу ли я зарегистрировать 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's presenter here.
mPresenter = new FirstPresenter(this);
...

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

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


person MilanNz    schedule 15.03.2017    source источник
comment
В примере кода в репозитории Android Blueprint вы увидите, что Presenters создается внутри Activity, но регистрация также будет выполняться внутри Fragment. См., например, TaskDetailActivity: github.com/googlesamples/android-architecture/blob/todo-mvp/ — мы также используем MVP в нашем приложении, и мы регистрация так же. Я не вижу никакой проблемы в том, чтобы сделать это так.   -  person Darwind    schedule 15.03.2017


Ответы (2)


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

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

view.setPresenter(T presenter); 

методы просмотра и Presenters зарегистрируйтесь для просмотра.

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

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

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

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

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

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

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

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

Почему действия не являются элементами пользовательского интерфейса? http://www.techyourchance.com/activities-android/

person savepopulation    schedule 15.03.2017
comment
Спасибо за подробный ответ! Поскольку вы кажетесь опытным разработчиком, у вас есть решение, как решить проблему с одним действием и несколькими фрагментами? - person MilanNz; 16.03.2017
comment
как я упоминал в своем ответе, если вам нужно несколько фрагментов в одном и том же действии, вы можете позволить действию создать новую транзакцию фрагмента фиксации фрагмента, создать презентатор и соединить их. но я не видел такой реализации в примерах Google. они реализуют 1 активность - 1 фрагмент. - person savepopulation; 16.03.2017

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

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

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

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

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

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

Дело в том, что если мне нужно иметь несколько фрагментов внутри одной активности хоста, я должен создать экземпляр каждого презентатора и передать его через свой 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()
    }
}

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

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

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

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

person Gastón Saillén    schedule 19.07.2019