Подтвердить что ты не робот

Android MVP open Activity from Presenter, анти-шаблон?

Будет ли это анти-шаблон, если из уровня Presenter я открою Activity?

Если да, должен ли я управлять навигацией приложения из уровня просмотра?

4b9b3361

Ответ 1

Да, это анти-mvp-шаблон. Основанный на пассивном виде в MVP, вы потеряли свою тестируемость, потому что вам не нужно иметь дело с каркасом Android в своем презентаторе.

Так что лучше управлять навигацией приложения с уровня просмотра.

class MyPresenter {
    MyPresenter.View view;

    void backButtonClicked() {
        view.navigateToHomeScreen();
    }

    public interface View {
        void navigateToHomeScreen();
    }
}

class MyActivity extends Activity implements MyPresenter.View {
    @Override
    void navigateToHomeScreen() {
        startActivity(...)
    }

    @OnClick(R.id.my_button)
    void onClick() {
        presenter.backButtonClicked();
    }
} 

Другим преимуществом этого способа является то, что будет легко заменить активность фрагментом или представлением.

Изменить 1:

Morgwai сказал, что этот способ нарушит разделение беспокойства и единоличной ответственности, но вы не можете иметь единой ответственности везде. Когда-нибудь вам нужно будет его нарушить. Вот пример из Google для MVP:

TaskDetailPresenter вызывает ShowEditTask, который ответственный за открытие нового Activity внутри TaskDetailFragment.

Но вы также можете использовать CommandPattern, который является лучшим подходом

interface NavigationCommand {
    void navigate();
}

Итак, Presenter будет использовать его, когда это необходимо.

Ответ 2

Как я писал в своем комментарии к принятому отвечу, я считаю, что управление навигацией с уровня представления является явным нарушением правила разделения интересов: представления должны содержать ТОЛЬКО методы обновления текущего экрана пользовательского интерфейса.

Проблема возникает из конструкции платформы Android, поскольку классы Activity и Fragment содержат оба метода для работы на экране пользовательского интерфейса и для отправки объектов намерения, которые запускают другие действия, такие как startActivity.

Чистым способом решения этой проблемы было бы создать некоторый интерфейс Navigator, который будет содержать методы, связанные с навигацией, активировать его и внедрить в презентаторов. Этот способ, по крайней мере, с точки зрения навигации инструкторов и манипулирования пользовательским интерфейсом будет разделен. Однако он может показаться странным с точки зрения деятельности: теперь они часто реализуют оба интерфейса (Navigator и View) и передают ссылку 2 раз ведущему. Если по этой причине вы решите управлять навигацией со своего уровня представления, по крайней мере, сохраните методы навигации отдельно от тех, которые используются для управления пользовательским интерфейсом: никогда не выполняйте навигацию и манипулирование пользовательским интерфейсом одним и тем же методом.

Ответ 3

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

Если есть какое-то условие того, какая деятельность должна быть запущена, вы можете использовать что-то вроде этого:

public class Presenter {

    private ViewsPresentation mViewsPresentation;

    public void someButtonClicked() {
        if (/*some condition*/) {
            mViewsPresentation.startFirstActivity();
        } else {
            mViewsPresentation.startSecondActivity();
        }
    }

    public interface ViewsPresentation {
        void startFirstActivity();
        void startSecondActivity();
    }

}

Ответ 4

Я сделал это решение (в Котлине):
Я создал интерфейс под названием ViewNavigator

interface ViewNavigator {
    fun navigateTo(target: Class<*>)
}

Затем я заставил интерфейс представления реализовать его.

interface View : ViewNavigator {
    //...
}

Тогда фактический вид (действие) может переопределить функцию navigateTo

override fun navigateTo(target: Class<*>) {
    startActivity(Intent(this, target))
}

Поэтому, когда я захочу перейти к какому-либо занятию, я могу просто написать это в классе докладчика. Например:

override fun onAnimationFinished() {
    view.navigateTo(HomeActivity::class.java)
}