JavaRush /Blogue Java /Random-PT /MVP em Android para os mais pequenos

MVP em Android para os mais pequenos

Publicado no grupo Random-PT
Quando comecei minha jornada como desenvolvedor Android, as palavras “Arquitetura de Aplicativos Móveis” me causaram profunda perplexidade, o Google e os artigos sobre Habré me levaram a uma depressão ainda maior - olho para o livro e não vejo nada. Acho que se você está lendo este artigo, já estudou esse quadro mais de uma vez e tentou entender o que está acontecendo: MVP em Android para os mais pequenos - 1O problema de entender a abordagem arquitetônica no desenvolvimento móvel, na minha opinião, está na abstração da própria arquitetura. Cada desenvolvedor tem sua própria visão de como implementar corretamente este ou aquele padrão. Exemplos mais ou menos decentes de implementação de MVP foram encontrados no setor de língua inglesa da Internet, o que não é surpreendente. Vejamos brevemente o que é o quê e passemos para um exemplo. Modelo - nível de dados. Não gosto de usar o termo “lógica de negócio”, por isso nas minhas aplicações chamo-o de Repositório e ele se comunica com o banco de dados e com a rede. Visualizar — nível de exibição. Será Activity , Fragment ou Custom View se você não gosta de dançar com pandeiro e interagir com o ciclo de vida. Deixe-me lembrá-lo que inicialmente todos os aplicativos Android estão subordinados à estrutura MVC , onde o Controller é uma Activity ou Fragment . Presenter é uma camada entre View e Model. A View transmite os eventos que lhe ocorrem, o apresentador os processa, se necessário, acessa o Modelo e retorna os dados para a View para renderização. Em relação ao Android e a um exemplo específico, destaco a parte importante – Contrato. Esta é a interface que descreve todas as interações entre os componentes acima. Para resumir a parte teórica:
  • Ver sabe sobre o Presenter;
  • O apresentador conhece View e Model (Repository);
  • Modelo por si só;
  • O contrato rege as interações entre eles.
Na verdade, o exemplo em si, para simplificar o experimento, ao clicar em um botão, iremos carregar uma linha do banco de dados e exibi-la em um TextView . Por exemplo, o banco de dados contém uma lista dos melhores restaurantes da cidade. Vamos começar com o contrato: vamos criar uma interface MainContract:
public interface MainContract {
    interface View {
        void showText();
    }

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

    interface Repository {
        String loadMessage();
    }
}
Por enquanto, estamos simplesmente destacando os 3 componentes da nossa aplicação futura e o que eles farão. A seguir descreveremos o Repositório:
public class MainRepository implements MainContract.Repository {

    private static final String TAG = "MainRepository";
    @Override
    public String loadMessage() {
        Log.d(TAG, "loadMessage()");
        /** Здесь обращаемся к БД or сети.
         * Я специально ничего не пишу, чтобы не загромождать пример
         * DBHelper'ами и прочими не относяшимеся к теме an objectми.
         * Поэтому я буду возвращать строку Сосисочная =)
         */
        return "Сосисочная у Лёхи»;
    }
}
Tudo fica claro com ele, apenas carregando e descarregando dados. O próximo é o apresentador:
public class MainPresenter implements MainContract.Presenter {
    private static final String TAG = "MainPresenter";

    //Компоненты MVP applications
    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()");
    }
}
Você se lembra que escrevi sobre dançar com pandeiro e o ciclo de vida? O Presenter vive enquanto vive o seu View, ao desenvolver cenários de usuário complexos, aconselho duplicar todos os callbacks do View no Presenter e chamá-los nos momentos apropriados, duplicando o ciclo de vida da Activity/Fragment, para entender a tempo o que precisa ser feito com os dados que estão atualmente pendurados no “interlayer”. E por fim, Visualize:
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()");
    }
}
O que está acontecendo?
  • A atividade, também conhecida como View, onCreate()cria uma instância do Presenter em um método e passa para seu construtor.
  • Quando um Presenter é criado, ele recebe explicitamente uma View e cria uma instância de Repository (a propósito, ele pode se tornar um Singleton)
  • Quando um botão é pressionado, o View bate no apresentador e diz: “O botão foi pressionado”.
  • O apresentador recorre ao Repositório: “Baixe essa porcaria para mim”.
  • O Repositório carrega e entrega as “coisas” ao Apresentador.
  • Apresentador vira para Visualizar: “Aqui estão os dados para você, desenhe-os”
É isso, pessoal. PS É importante delinear claramente as responsabilidades entre os componentes. Por exemplo, em um dos meus projetos de treinamento, ao clicar em um botão, foi necessário alterar dados do banco de dados. O modelo foi descrito por uma classe POJO, passei informações sobre a localização da view, que é responsável pelas informações do objeto na tela, o Presenter procurou esse objeto na lista e enviou para ser gravado no Repositório. Tudo parece lógico? Mas meu mentor apontou o seguinte: o Repositório SÓ deve escrever e ler, não deve extrair as informações necessárias do POJO e decidir o que precisa escrever. O Apresentador deve fornecer apenas as informações da gravação e nada mais. Não existe uma estrutura rígida para a implementação da arquitetura: experimente, experimente, procure o que é mais conveniente para você pessoalmente. E não se esqueça de mostrar aos seus camaradas seniores a revisão do código =) O exemplo está disponível no GitHub: https://github.com/admitrevskiy/MVP_Example
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION