JavaRush /Blog Java /Random-ES /MVP en Android para los más pequeños

MVP en Android para los más pequeños

Publicado en el grupo Random-ES
Cuando comencé mi viaje como desarrollador de Android, las palabras "Arquitectura de aplicaciones móviles" me causaron un profundo desconcierto, Google y los artículos sobre Habré me llevaron a una depresión aún mayor: miro el libro y no veo nada. Creo que si estás leyendo este artículo, ya habrás estudiado esta imagen más de una vez y habrás intentado comprender lo que está sucediendo: MVP en Android para los más pequeños - 1el problema de comprender el enfoque arquitectónico en el desarrollo móvil, en mi opinión, radica en la abstracción de la arquitectura misma. Cada desarrollador tiene su propia visión de cómo implementar correctamente tal o cual patrón. Se encontraron ejemplos más o menos decentes de implementación de MVP en el sector de Internet de habla inglesa, lo cual no es sorprendente. Veamos brevemente qué es qué y pasemos a un ejemplo. Modelo - nivel de datos. No me gusta usar el término “lógica de negocios”, por eso en mis aplicaciones lo llamo Repositorio y se comunica con la base de datos y la red. Ver : nivel de visualización. Será Actividad , Fragmento o Vista personalizada si no te gusta bailar con una pandereta e interactuar con el ciclo de vida. Permítanme recordarles que inicialmente todas las aplicaciones de Android están subordinadas a la estructura MVC , donde el Controlador es una Actividad o Fragmento . Presentador es una capa entre Vista y Modelo. La Vista transmite los eventos que le ocurren, el presentador los procesa, si es necesario, accede al Modelo y devuelve los datos a la Vista para su renderización. En relación con Android y un ejemplo específico, destacaré la parte importante: Contrato. Esta es la interfaz que describe todas las interacciones entre los componentes anteriores. Para resumir la parte teórica:
  • View conoce Presenter;
  • El presentador conoce la Vista y el Modelo (Repositorio);
  • Modelo por sí mismo;
  • El contrato rige las interacciones entre ellos.
En realidad, el ejemplo en sí, para simplificar el experimento, al hacer clic en un botón, cargaremos una fila de la base de datos y la mostraremos en un TextView . Por ejemplo, la base de datos contiene una lista de los mejores restaurantes de la ciudad. Comencemos con el contrato: creemos una interfaz MainContract:
public interface MainContract {
    interface View {
        void showText();
    }

    interface Presenter {
        void onButtonWasClicked();
        void onDestroy();
    }

    interface Repository {
        String loadMessage();
    }
}
Por ahora, simplemente destacamos los 3 componentes de nuestra futura aplicación y lo que harán. A continuación describiremos el Repositorio:
public class MainRepository implements MainContract.Repository {

    private static final String TAG = "MainRepository";
    @Override
    public String loadMessage() {
        Log.d(TAG, "loadMessage()");
        /** Здесь обращаемся к БД o сети.
         * Я специально ничего не пишу, чтобы не загромождать пример
         * DBHelper'ами и прочими не относяшимеся к теме un objetoами.
         * Поэтому я буду возвращать строку Сосисочная =)
         */
        return "Сосисочная у Лёхи»;
    }
}
Todo está claro con él, solo cargar y descargar datos. El siguiente es el presentador:
public class MainPresenter implements MainContract.Presenter {
    private static final String TAG = "MainPresenter";

    //Компоненты MVP aplicaciones
    private MainContract.View mView;
    private MainContract.Repository mRepository;

    //Сообщение
    private String message;


    //Обрати внимание на аргументы конструктора - мы передаем экземпляр View, а Repository просто создаём конструктором.
    public MainPresenter(MainContract.View mView) {
        this.mView = mView;
        this.mRepository = new MainRepository();
        Log.d(TAG, "Constructor");
    }

    //View сообщает, что кнопка была нажата
    @Override
    public void onButtonWasClicked() {
        message = mRepository.loadMessage();
        mView.showText(message);
        Log.d(TAG, "onButtonWasClicked()");
    }

    @Override
    public void onDestroy() {
        /**
         * Если бы мы работали например с RxJava, в этом классе стоило бы отписываться от подписок
         * Кроме того, при работе с другими методами асинхронного андроида,здесь мы боремся с утечкой контекста
         */

        Log.d(TAG, "onDestroy()");
    }
}
¿Recuerdas que escribí sobre bailar con pandereta y el ciclo de la vida? El Presentador vive tanto como su Vista, al desarrollar escenarios de usuario complejos, le aconsejo que duplique todas las devoluciones de llamada de Vista en el Presentador y las llame en los momentos apropiados, duplicando el ciclo de vida Actividad/Fragmento, para comprender a tiempo lo que necesita. que hacer con los datos que están colgados actualmente en la "capa intermedia". Y finalmente, Ver:
public class MainActivity extends AppCompatActivity implements MainContract.View {

    private static final String TAG = "MainActivity";

    private MainContract.Presenter mPresenter;

    private Button mButton;

    private TextView myTv;

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

        //Создаём Presenter и в аргументе передаём ему this - эта Activity расширяет интерфейс MainContract.View
        mPresenter = new MainPresenter(this);

        myTv = (TextView) findViewById(R.id.text_view);
        mButton = (Button) findViewById(R.id.button);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.onButtonWasClicked();
            }
        });
        Log.d(TAG, "onCreate()");
    }

    @Override
    public void showText(String message) {
        myTv.setText(message);
        Log.d(TAG, "showMessage()");
    }

    //Вызываем у Presenter метод onDestroy, чтобы избежать утечек контекста и прочих неприятностей.
    @Override
    public void onDestroy() {
        super.onDestroy();
        mPresenter.onDestroy();
        Log.d(TAG, "onDestroy()");
    }
}
¿Qué está sucediendo?
  • La actividad, también conocida como Vista, onCreate()crea una instancia de Presentador en un método y se pasa a su constructor.
  • Cuando se crea un Presentador, recibe explícitamente una Vista y crea una instancia de Repositorio (por cierto, se puede convertir en un Singleton)
  • Cuando se presiona un botón, la Vista llama al presentador y dice: "Se presionó el botón".
  • El presentador recurre al repositorio: "Descarga esta basura por mí".
  • El Repositorio carga y entrega las "cosas" al Presentador.
  • El presentador pasa a Ver: "Aquí están los datos para usted, dibújelos"
Eso es todo, muchachos. PD: Es importante delimitar claramente las responsabilidades entre los componentes. Por ejemplo, en uno de mis proyectos de formación, al hacer clic en un botón, era necesario cambiar datos en la base de datos. El modelo fue descrito por una clase POJO, pasé información sobre la ubicación de la vista, que es responsable de la información sobre el objeto en la pantalla, Presenter buscó este objeto en la lista y lo envió para escribirlo en el Repositorio. ¿Parece todo lógico? Pero mi mentor señaló lo siguiente: el Repositorio SÓLO debe escribir y leer, no debe extraer la información necesaria del POJO y decidir qué necesita escribir. El Presentador deberá darle únicamente la información a grabar y nada más. No existe un marco estricto para implementar la arquitectura: experimente, pruebe, busque lo que le resulte más conveniente personalmente. Y no olvide mostrárselo a sus camaradas superiores en la revisión del código =) El ejemplo está disponible en GitHub: https://github.com/admitrevskiy/MVP_Example
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION