Android MVP简易demo

10 篇文章 0 订阅
首先,了解下一个java的原则,这便于后面理解presenter和view、model之间的依赖。
<!--依赖倒置原则-->
* <!--1.高层模块不依赖低层模块, 两者都依赖于抽象.-->
* <!--类A直接依赖类B, 假如要将类A改为依赖类C, 则必须通过修改类A的代码来达成;-->
* <!--这种场景下: 类A一般是高层模块, 负责复杂的业务逻辑; 类B和类C是低层模块, 负责基本的原子操作;-->
* <!--假如修改类A, 会给程序带来不必要的风险;-->
* <!--解决方案: 将类A修改为依赖接口I, 类B和类C各自实现接口I;-->
* <!--类A通过接口I间接与类B或者类C发生联系, 则会大大降低修改类A的几率;-->
* <!--2.抽象不依赖于细节.-->
* <!--3.细节应该依赖于抽象.-->
* <!--这三者请遵循依赖倒置原则: presenter子类依赖view和model的父类, 不要直接去依赖这二者的子类-->

这个是mvp模式的类图依赖逻辑: 很明显, presenter和view、presenter和model都是双向依赖, 所以需要相互注入, 后面的代码注释中有说明注入方式。

正题:mvp现在比较好的方式是契约模式,所以直接上契约模式

* <!--※契约的抽象思考:
* <!--1.model中要调用什么方法, 做什么操作? 比如这里是去发指令去请求耗时数据
* <!--2.View中要显示什么? 比如这里view要显示进度条, 完成后的数据
* <!--3.presenter中要如何调度model和view?
* <!--------比如这里就是调度model去拿数据, 调度view去显示进度、显示拿到的数据

1.这是契约接口,里面定义了LoadData这个功能的mvp契约,model、view、presenter的接口。

public interface LoadDataContract {
    interface Model {
        /**
         * 逻辑程序开始真正去拿数据
         *
         * @param callback
         */
        void requestData(LoadDataModel.LoadDataCallback callback);
    }

    /**
     * Activity, fragment, view都认为是view
     */
    interface View {
        /**
         * 界面告诉用户开始加载数据
         *
         * @param msg
         */
        void showLoadingProgress(String msg);

        /**
         * 界面显示数据获取成功
         *
         * @param text
         */
        void showData(String text);

        /**
         * 界面显示数据获取失败
         *
         * @param text
         */
        void showFailureMsg(String text);
    }

    interface Presenter {
        /**
         * 最有可能就是点击某个Button去拿数据
         */
        void loadData();

        /**
         * 注意释放数据, 不要造成上下文泄露的情况, 比如Activity.onDestroy, Fragment.onDestroy
         */
        void destroy();
}

 

2.再看presenter的实现类

public class LoadDataPresenter implements LoadDataContract.Presenter {
    private static final String TAG = "LoadDataPresenter";
    private LoadDataContract.View mView;
    private LoadDataContract.Model mModel;
    /**
     * 这里实现了model实现类中定义的内部接口, 这样就可以将presenter注入model, 实现model依赖presenter
     * 而presenter直接持有model顶级父类接口, 这样就可以将model注入presenter, 实现了presenter依赖model
     * 从而实现了model和presenter的双向依赖
     */
    private LoadDataModel.LoadDataCallback loadDataCallback = new LoadDataModel.LoadDataCallback() {
        @Override
        public void success(String taskId) {
            mView.showData(taskId);
        }

        @Override
        public void failure(String eMsg) {
            mView.showFailureMsg(eMsg);
        }
    };

    /**
     * 这里直接将view注入presenter, 实现presenter依赖view的类图依赖, 那么要构造presenter实例对象, 
     * 也需要在view的实现类中去构造presenter, 这就可以实现viewpresenter的依赖,那么类图的双向依赖就达成了。
     */
    public LoadDataPresenter(LoadDataContract.View view) {
        mView = view;
        mModel = new LoadDataModel();
    }

    @Override
    public void loadData() {
        // 界面告诉用户开始加载数据
        mView.showLoadingProgress("加载数据中");
        // 逻辑程序开始真正去拿数据
        mModel.requestData(loadDataCallback);
    }

    @Override
    public void destroy() {
        mView = null;
        loadDataCallback = null;
        mModel = null;
    }
}

这个类里面直接依赖了model、view的顶级接口,符合依赖倒置原则;

 

3.再来看model的实现

public class LoadDataModel implements LoadDataContract.Model {

    @Override
    public void requestData(LoadDataCallback callback) {
        // 数据获取操作,如数据库查询、网络加载等
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 模拟耗时操作, 这10s时间内, 真是场景下, 你可以做任何事情来替换这10s休眠
                    // 比如: 请求网络数据, 大量数据排序, 查询数据库等
                    Thread.sleep(10000L);
                    // 请求完成, 获取到了数据
                    String data = "this is the data of requesting";
                    // 将获取的数据通过接口反馈出去
                    callback.success(data);
                } catch (Exception e) {
                    e.printStackTrace();
                    // 获取数据失败的回调
                    callback.failure("the data request failed");
                }
            }
        }).start();
    }

    /**
     * 用于回传请求的数据的回传
     */
    public interface LoadDataCallback {
        /**
         * 数据请求成功
         *
         * @param taskId
         */
        void success(String taskId);

        /**
         * 数据请求失败
         *
         * @param eMsg
         */
        void failure(String eMsg);
    }
}

在model的实现类中,定义了一个内部接口,用来向外传递LoadData的状态,其实最主要是给presenter用的LoadDataCallback,这样就能将presenter注入model中,也就是实现了model也依赖presenter。

 

4.接着看view的实现,直接认为activity就是view

public class LoadDataViewActivity extends Activity implements LoadDataContract.View {
    private static final String TAG = "LoadDataViewActivity";
    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_load_data:
                    if (presenter != null) {
                        presenter.loadData();
                    }
                    break;
                default:
                    break;
            }
        }
    };

    private LoadDataContract.Presenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 在view中初始化presenter, 并且注入view
        presenter = new LoadDataPresenter(this);
        findViewById(R.id.btn_load_data).setOnClickListener(listener);
    }

    @Override
    public void showLoadingProgress(String msg) {
        // 这里去运行ProgressView
        Log.i(TAG, "you can show the progressView of the progress.");
    }

    @Override
    public void showData(String text) {
        // 这里去通过ListView显示你获取到的数据, 或者其他格式数据对应的View.
        Log.i(TAG, "you can add data to the ListView and adapter.");
    }

    @Override
    public void showFailureMsg(String text) {
        // 这里显示获取失败的信息, 提示用户失败原因等.
        Log.i(TAG, "you can show the failed text on the TextView.");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (presenter != null) {
            presenter.destroy();
            presenter = null;
        }
    }
}

我们需要思考一个问题:

* <!--※用户是如何调用mvp模式的?
* <!--作为用户, 能接触到的只有view, 所以, 用户调用mvp模式应该是:
* <!--user操作view -> view <-> presenter <-> model
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值