android 通过改造一个简单项目,浅入了解一下mvp模式

申明:低级码农问题解决中的参考和解决后的小结,仅用于个人记录,能力有限,可能有些错误,缺陷不自知,欢迎在评论中指正,谢谢!

简单了解mvc

mvp是对android中mvc的不足进行的优化。为了更容易理解,先简单介绍一下android中的mvc模式。

Model:狭义讲就是bean数据,数据的获取和存储由充当Control层的Activity完成,这导致Activity太庞大了。所以现在把数据的获取和存储,封装网络框架和数据库组件中,把他们也算作Model。

View:布局文件。但是布局文件的功能太弱了,Activity也必须承担部分View层的功能。

Control:毫无悬念由Activity充当。接受用户操作,请求数据。获取到数据,更新到UI上。

下图是mvc模式的结构。

下面是一个简单的例子,点击按钮获取数据,然后更新到UI上。这个例子中,Activity的工作很繁杂,响应用户操作,然后获取数据,在接收数据并更新到UI上。

public class SecondActivity extends Activity {

    Handler handler;
    TextView tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.secondactivity);
        setTitle("second");
        handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 0) {
                    String str = (String) msg.obj;
                    tv.setText(str);
                }
            }
        };

        tv = (TextView) findViewById(R.id.tv);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        StringBuilder str = new StringBuilder();
                        for (int i = 0; i < 5; i++) {
                            str.append("学号 ").append(i).append("\n");
                        }
                        Message msg = handler.obtainMessage(0);
                        msg.obj = str.toString();
                        msg.sendToTarget();
                    }
                }.start();
            }
        });
    }
}
View Code

 简介mvp

mvp的优点是简化了Activity,Activity只负责展示数据和用户交互。真正意义上隔离了View和Model。缺点是很依赖场景的抽象,然后就是没增加一个场景,要增加很多接口方法。结构如下:

 

改造为mvp的过程

包括对view,model,presenter三部分。

View应该根据实际需要的UI变化的场景,合理提供更新UI的接口方法。注意是更新场景提供接口,而不是根据控件。比如开始获取数据时,UI要做的改变如显示progressbar、按钮不可点击、旧的数据的清空;获取到数据后,隐藏progressbar,显示数据等。要根据这两个场景提供方法,而不是分别提供progressbar,按钮,显示数据的ListView的方法,让Presenter决定哪些要变,怎么变。

本文定义了一个IView接口,Activity作为View层,实现此接口。

public interface IView {
    void refreshUI(String s);
    void showProgressbar();

    /*
    根据场景,细化更新UI的方法
    void refreshPartUI();
    void showProgressbar();
    void hideProgressbar();
     */
}
View Code
/** Activity实现IView */
public class SecondActivity extends Activity implements IView {

    TextView tv;

    Presenter presenter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.secondactivity);
        setTitle("second");
        presenter = new Presenter(SecondActivity.this);
        tv = (TextView) findViewById(R.id.textview);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 调用Presenter获取数据
                presenter.getData();
            }
        });
    }

    /*
     * 实现IView的接口方法
     */

    @Override
    public void refreshUI(final String s) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tv.setText(s);
            }
        });
    }

    @Override
    public void showProgressbar() {
        // 这里弹出Progressbar
    }
}
View Code

Model也是根据View中定义的场景,提供对应获取数据的方法,获取到数据后,通知Presenter数据已经拿到。本文通知Presenter的方式是提供一个回调接口,Presenter实现此回调。

public class Model {
    CallBack callBack;

    public Model(CallBack callBack) {
        this.callBack = callBack;
    }

    public void requestData() {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list.add("学号 " + i + "\n");
        }
        if (callBack != null) {
            String str = new Gson().toJson(list);
            callBack.onGetData(str);
        }
    }

    /** 通过回到接口通知Presenter数据获取完成 */
    public interface CallBack {
        void onGetData(String str);
    }
}
View Code

Presenter,要做的是调用View的全部方法,实现Model的内部回调接口。View中定义的更新UI的方法,全部应该在Presenter中被调用,通过Presenter内部持有的View对象。没有被调用的方法,就是多余的方法。调用时需要进行比较复杂的判断来确定调用什么方法,就是把UI更新逻辑放到Presenter中了。这两种情况都是场景没有抽象好的情况。

/**
 * 连接View层和Model层,有两部分核心功能
 * 1、对View层提供获取数据的方法,该方法内部调用Model完成
 * 2、接受Model的数据变化,通知View更新UI
 */
public class Presenter implements Model.CallBack {
    Model model;
    IView view;

    public Presenter(IView view) {
        this.view = view;
        model = new Model(this);
    }

    /** 对View暴露,内部调用Model */
    public void getData() {
        view.showProgressbar();
        model.requestData();
    }

    /** 接收Model的变化,通过内部持有的View对象更新UI(是View更新的UI) */
    @Override
    public void onGetData(String str) {
        view.refreshUI(str);
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/hellodingc/p/12802428.html
今日推荐