android mvp

In this tutorial, we’ll be discussing the android MVP principles and develop an application based on it. Since the start, we’ve been developing applications by adding all the business logic inside the Activity. Let’s analyze the cons of our current approach before digging into the new principles.

在本教程中,我们将讨论android MVP原理,并基于此原理开发应用程序。 从一开始,我们就通过在Activity中添加所有业务逻辑来开发应用程序。 在深入探讨新原理之前,让我们分析一下当前方法的弊端。

Android MVP (Android MVP)

With our current approach, the MainActivity class contains all the implementation logic of our application. We’ve been using stuff ranging from Retrofit callbacks to data models(SharedPref, POJO classes) all inside the Activity class.

使用我们当前的方法,MainActivity类包含我们应用程序的所有实现逻辑。 我们一直在Activity类中使用从Retrofit回调到数据模型(SharedPref,POJO类)的内容。

Eventually, our Activities become god classes and cause problems in maintainability, readability, scalability and refactoring an already bloated code.

最终,我们的活动成为了上帝的职业,并在可维护性,可读性,可伸缩性和重构已经肿的代码方面引起了问题。

Unit testing gets tough since the implementation logic is tightly coupled with the Android APIs. This is where MVP ( Model View Presenter) comes in handy. It allows us to write a clean and flexible code base while giving the luxury to switch any part of the code without much hassle.

由于实现逻辑与Android API紧密结合,因此单元测试变得越来越困难。 这是MVP(模型视图演示器)派上用场的地方。 它使我们能够编写简洁,灵活的代码库,同时又可以轻松切换代码的​​任何部分,而无须麻烦。

模型视图演示者 (Model View Presenter)

Model View Presenter divides our application into three layers namely the Model, View and Presenter.

Model View Presenter将我们的应用程序分为三层,即Model,View和Presenter。

  1. Model: This handles the data part of our application

    模型 :处理我们应用程序的数据部分
  2. Presenter: It acts as a bridge that connects a Model and a View.

    演示者 :它充当连接模型和视图的桥梁。
  3. View: This is responsible for laying out views with the relevant data as instructed by the Presenter

    视图 :这负责按照演示者的指示使用相关数据布置视图

Note: The View never communicates with Model directly.

注意 :View从不直接与Model通信。

Android MVP架构 (Android MVP Architecture)

The diagram below depicts a basic MVP structure.

android mvp

下图描述了基本的MVP结构。

Android MVP准则 (Android MVP Guidelines)

  1. Activity, Fragment and a CustomView act as the View part of the application.

    Activity,Fragment和CustomView充当应用程序的View部分。
  2. The Presenter is responsible for listening to user interactions (on the View) and model updates (database, APIs) as well as updating the Model and the View.

    演示者负责侦听用户交互(在View上)和模型更新(数据库,API),以及更新Model和View。
  3. Generally, a View and Presenter are in a one to one relationship. One Presenter class manages one View at a time.

    通常,视图和演示者之间是一对一的关系。 一个Presenter类一次管理一个View。
  4. Interfaces need to be defined and implemented to communicate between View-Presenter and Presenter-Model.

    需要定义和实现接口以在View-Presenter和Presenter-Model之间进行通信。
  5. The Presenter is responsible for handling all the background tasks. Android SDK classes must be avoided in the presenter classes.

    演示者负责处理所有后台任务。 在presenter类中必须避免使用Android SDK类。
  6. The View and Model classes can’t have a reference of one another.

    View和Model类不能互相引用。

Having covered the theory of MVP architecture, let’s build an android MVP app now.

涵盖了MVP体系结构的理论之后,让我们现在构建一个android MVP应用程序。

Android MVP示例应用程序项目结构 (Android MVP Example App Project Structure)

The android mvp project consists of 3 interface files (also known as contracts). The Impl files are where the interfaces are implemented.

android mvp项目包含3个接口文件(也称为合同)。 Impl文件是实现接口的位置。

We’ll be creating a single activity application that’ll display a random quote from a list of quotes present in an ArrayList. We’ll see how the presenter manages to keep the business logic of the application away from the activity class.

我们将创建一个活动应用程序,该应用程序将显示ArrayList中存在的引号列表中的随机引号。 我们将看到演示者如何管理使应用程序的业务逻辑远离活动类。

Note: Interactors are classes built for fetching data from your database, web services, or any other data source.

注意: Interactor是为从数据库,Web服务或任何其他数据源中获取数据而构建的类。

Android MVP应用程式程式码 (Android MVP app code)

The code for the activity_main.xml layout is given below.

下面给出了activity_main.xml布局的代码。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.journaldev.hellomvp.MainActivity">

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Implementing MVP Pattern in this Application."
        app:layout_constraintBottom_toBottomOf="parent"
        android:padding="8dp"
        android:gravity="center"
        android:textAppearance="?android:attr/textAppearanceSearchResultTitle"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:id="@+id/textView" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GET NEXT QUOTE"
        android:layout_margin="@android:dimen/notification_large_icon_height"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

The code for the GetQuoteInteractor interface is given below.

下面给出了GetQuoteInteractor接口的代码。

package com.journaldev.hellomvp;

public interface GetQuoteInteractor {

    interface OnFinishedListener {
        void onFinished(String string);
    }

    void getNextQuote(OnFinishedListener listener);
}

It contains a nested interface onFinishedListener. We’ll be using a handler inside our GetQuoteInteractorImpl.java below. On completion of the handler, the above onFinished method would be triggered.

它包含一个嵌套接口onFinishedListener。 我们将在下面的GetQuoteInteractorImpl.java中使用处理程序。 处理程序完成后,将触发上述onFinished方法。

package com.journaldev.hellomvp;

import android.os.Handler;

import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class GetQuoteInteractorImpl implements GetQuoteInteractor {

    private List<String> arrayList = Arrays.asList(
            "Be yourself. everyone else is already taken.",
            "A room without books is like a body without a soul.",
            "You only live once, but if you do it right, once is enough.",
            "Be the change that you wish to see in the world.",
            "If you tell the truth, you don't have to remember anything."
    );

    @Override
    public void getNextQuote(final OnFinishedListener listener) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                listener.onFinished(getRandomString());
            }
        }, 1200);
    }

    private String getRandomString() {

        Random random = new Random();
        int index = random.nextInt(arrayList.size());

        return arrayList.get(index);
    }
}

The MainView.java interface is defined below.

MainView.java接口在下面定义。

package com.journaldev.hellomvp;

public interface MainView {

    void showProgress();

    void hideProgress();

    void setQuote(String string);
}

showProgress() and hideProgress() would be used for displaying and hiding the progressBar while the next random quote is fetched from the GetQuoteInteractorImpl class.

当从GetQuoteInteractorImpl类获取下一个随机报价时,将使用showProgress()hideProgress()来显示和隐藏progressBar

setQuote() will set the random string on the textView.

setQuote()将在setQuote()设置随机字符串。

The code for the MainPresenter.java interface is given below.

MainPresenter.java接口的代码如下。

package com.journaldev.hellomvp;

public interface MainPresenter {

    void onButtonClick();

    void onDestroy();
}

The MainPresenterImpl.java class is defined below.

MainPresenterImpl.java类在下面定义。

package com.journaldev.hellomvp;

public class MainPresenterImpl implements MainPresenter, GetQuoteInteractor.OnFinishedListener {

    private MainView mainView;
    private GetQuoteInteractor getQuoteInteractor;

    public MainPresenterImpl(MainView mainView, GetQuoteInteractor getQuoteInteractor) {
        this.mainView = mainView;
        this.getQuoteInteractor = getQuoteInteractor;
    }

    @Override
    public void onButtonClick() {
        if (mainView != null) {
            mainView.showProgress();
        }

        getQuoteInteractor.getNextQuote(this);
    }

    @Override
    public void onDestroy() {
        mainView = null;
    }

    @Override
    public void onFinished(String string) {
        if (mainView != null) {
            mainView.setQuote(string);
            mainView.hideProgress();
        }
    }
}

The above class implements the Presenter and nested interface from GetQuoteInteractor. Moreover it instantiates the MainView and GetQuoteInteractor interfaces (View and Model respectively).

上面的类实现了GetQuoteInteractor的Presenter和嵌套接口。 此外,它实例化MainViewGetQuoteInteractor接口(分别为View和Model)。

onButtonClick method would be triggered in the MainActivity class when the button is clicked and will display a progressBar while it gets the next random quote.

单击按钮时,将在MainActivity类中触发onButtonClick方法,并在获取下一个随机引用时显示progressBar

onDestroy() method would be invoked inside the lifecycle method onDestroy() of the MainActivity.

onDestroy()方法将在MainActivity的生命周期方法onDestroy()中调用。

onFinished() method gets called when the handler is completed inside the GetQuoteInteractorImpl. It returns the string which will be displayed in the TextView using the MainView’s instance.

当处理程序在GetQuoteInteractorImpl中完成时,将调用onFinished()方法。 它返回将使用MainView的实例显示在TextView中的字符串。

The code for the MainActivity.java which implements MainView interface is given below.

下面给出了实现MainView接口的MainActivity.java代码。

package com.journaldev.hellomvp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import static android.view.View.GONE;

public class MainActivity extends AppCompatActivity implements MainView {

    private TextView textView;
    private Button button;
    private ProgressBar progressBar;
    MainPresenter presenter;

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

        textView = (TextView) findViewById(R.id.textView);
        button = (Button) findViewById(R.id.button);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        presenter = new MainPresenterImpl(this, new GetQuoteInteractorImpl());

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                presenter.onButtonClick();
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.onDestroy();
    }

    @Override
    public void showProgress() {
        progressBar.setVisibility(View.VISIBLE);
        textView.setVisibility(View.INVISIBLE);
    }

    @Override
    public void hideProgress() {
        progressBar.setVisibility(GONE);
        textView.setVisibility(View.VISIBLE);
    }

    @Override
    public void setQuote(String string) {
        textView.setText(string);
    }
}

showProgress() and hideProgress() methods shows and hides the textView as well to prevent overlapping the current text and the progressBar.

showProgress()hideProgress()方法还显示和隐藏hideProgress() ,以防止当前文本和progressBar重叠。

Note: The above class contains is now devoid of the business logic and is responsible for only updating the UI based on the changes triggered by the Presenter layer.

注意:上面的类包含的内容现在没有业务逻辑,仅负责根据Presenter层触发的更改来更新UI。

The output of the above android MVP application is given below.

android mvp pattern app example

上面的android MVP应用程序的输出如下。

Note: Google recommends to keep a single contract interface file for the Model View and Presenter.

注意:Google建议为Model View and Presenter保留一个合同界面文件。

So let’s club the interfaces defined above into one.

因此,让我们将上面定义的接口合并为一个。

The project structure now looks like this:

android MVP hello world app

现在,项目结构如下所示:

The code for the MainContract.java interface is given below.

MainContract.java接口的代码如下。

package com.journaldev.hellomvp;

public interface MainContract {

    interface MainView {
        void showProgress();

        void hideProgress();

        void setQuote(String string);
    }

    interface GetQuoteInteractor {
        interface OnFinishedListener {
            void onFinished(String string);
        }

        void getNextQuote(OnFinishedListener onFinishedListener);
    }

    interface Presenter {
        void onButtonClick();

        void onDestroy();
    }
}

This brings an end to this tutorial. There’s a lot more to explore in MVP pattern that we’ll be discussing soon.

本教程到此结束。 关于MVP模式,还有很多要探讨的内容,我们将很快讨论。

You can download the Android MVP Hello World Project from the link below.

您可以从下面的链接下载Android MVP Hello World项目

Reference: Wikipedia

参考: 维基百科

翻译自: https://www.journaldev.com/14886/android-mvp

android mvp

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐