Android中MVP模式的使用及内存泄漏原因分析(一)

正常情况

public class MainActivity extends AppCompatActivity implements RequestView{

    @BindView(R.id.textView)
    TextView mTextView;
    @BindView(R.id.button)
    Button mButton;

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

    public void clickRequest() {
        (new RetrofitUtils())
                .getRetrofit("http://10.21.159.179:8080/")
                .create(LoginAPI.class)
                .login("136284008", "xbh")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<JSONObject>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onNext(JSONObject jsonObject) {
                        mTextView.setText(jsonObject.toString());
                    }
                });
    }

    @OnClick(R.id.button)
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                clickRequest();
                break;
        }
    }

就是最简单的点击Button,网络请求(采用rxjava+retrofit2),把获取的json或者错误信息显示在TextView中


现在用MVP来写

先写V层,它是需要让MainActivity去实现的

public interface RequestView {
    void requestLoading();
    void resultSuccess(JSONObject object);
    void resultFailure(String errorMsg);
}
分别是请求中 请求完成 请求错误


在看M层

public class RequestModel {
    private static final String BASE_URL = "http://10.19.71.204:8080/";

    public void loginRequest(String userName, String userPassword,
                        Subscriber<JSONObject> subscriber) {
        (new RetrofitUtils())
                .getRetrofit(BASE_URL)
                .create(LoginAPI.class)
                .login(userName, userPassword)
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}
直接把我们的网络请求放在这里了。由于subscriber是rxjava+retrofit2的回调完成后的操作,所以也可以当成参数传。


再看看P层

public class RequestPresenter {
    private final RequestView mRequestView;
    private final RequestModel mRequestModel;

    public RequestPresenter(RequestView mRequestView) {
        this.mRequestView = mRequestView;
        this.mRequestModel = new RequestModel();
    }

    public void clickRequest(String userName, String userPassword) {
        mRequestView.requestLoading();
        mRequestModel.loginRequest(userName, userPassword, new Subscriber<JSONObject>() {
            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                mRequestView.resultFailure(e.getMessage());
            }

            @Override
            public void onNext(JSONObject object) {
                mRequestView.resultSuccess(object);
            }
        });
    }
}
由于它是连接者嘛,所以等于是连接业务和UI的纽带,所以他内部会维护M层和C层。


现在再来看一下我们的MainActivity,已经面目全非了

public class MainActivity extends AppCompatActivity implements RequestView{

    @BindView(R.id.textView)
    TextView mTextView;
    @BindView(R.id.button)
    Button mButton;

    private RequestPresenter presenter;

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

        presenter = new RequestPresenter(this);
    }

    @OnClick(R.id.button)
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                presenter.clickRequest("136284008", "xbh");
                break;
        }
    }

    private ProgressDialog dialog;

    @Override
    public void requestLoading() {
        dialog = ProgressDialog.show(this, "提示", "正在登陆中", false, true);
    }

    @Override
    public void resultSuccess(JSONObject object) {
        mTextView.setText(object.toString());
        dialog.cancel();
    }

    @Override
    public void resultFailure(String errorMsg) {
        mTextView.setText(errorMsg);
        dialog.cancel();
    }
}
仅仅只剩下了点击事件和完成点击事件后的回调操作了,使得你想做业务就专门做业务,UI和业务完全分离,舒服诶。


最后谈一下为什么会内存泄漏。

假如说网速很卡,你这个请求请求了10秒,但是在这10秒的过程中,我们直接把这个activity给关了,但是Presenter依然持有View的引用

public RequestPresenter(RequestView mRequestView) {
    this.mRequestView = mRequestView;
    this.mRequestModel = new RequestModel();
}

注意哦!P层的构造方法里是传了一个V层的引用进来,也就是说P层一直握住V层的地址。而且是强引用,所以activity对象在堆栈区中就根本无法释放了!因为还有人在用!解决方法是在onDestory中增加解绑操作即可。后面会讲。(可能有人会问M层怎么不会也内存泄漏。好吧,如果你能让M层的类突然终止,那么他这个情况肯定也就 内存泄漏了)


最后解析下调用流程

v层 clickrequest

public void clickRequest(String userName, String userPassword) {
    mRequestView.requestLoading();
    mRequestModel.loginRequest(userName, userPassword, new Subscriber<JSONObject>() {
        @Override
        public void onCompleted() {
        }

        @Override
        public void onError(Throwable e) {
            mRequestView.resultFailure(e.getMessage());
            mRequestView.resultFinish();
        }

        @Override
        public void onNext(JSONObject object) {
            mRequestView.resultSuccess(object);
            mRequestView.resultFinish();
        }
    });
}
所以会按顺序执行。其中第loding个和第finish个(我来我新加的,完成回调)是直接就执行他自己方法。而success,failure涉及到网络请求,就先执行了M层,扔进去一个回调。这里就相当于接口回调了。当M层的代码执行到subscriber的时候

public void loginRequest(String userName, String userPassword,
                    Subscriber<JSONObject> subscriber) {
    (new RetrofitUtils())
            .getRetrofit(BASE_URL)
            .create(LoginAPI.class)
            .login(userName, userPassword)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
}
就执行这个回调了。subscriber可以看成是 接口.方法名。而我们传进去的就可以看成是一个接口new 接口{方法名()}。

github地址:https://github.com/xubinhong/MVP2

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值