MVP架构设计模式1

在实际的开发过程中,常用到的设计模式有MVC、MVP、MVVM3种设计模式,在MVC设计模式中,Activity处于C层,却往往要兼顾V和C的2部分责任,是的C层和V层的耦合性太高,导致Activity或者Fragment层的代码臃肿,不具备扩展性,因此选择使用MVP、MVVM设计模式成为主流模式。

从本节开始,就介绍一下MVP设计模式的使用。在MVP模式中同样是分为3个角色:
M:Model层,主要负责数据的处理,包括联网操作,数据库等;
V:View层,主要包括Activity、Fragment;
P:Presenter层,主要负责和M层和V层交互。

其实在使用MVP结构设计时,最主要的思想就是接口设计,在MVC中,C往往完成View和C的业务逻辑功能,在MVP中,往往是将View层抽象为接口,将业务逻辑抽象成Presenter层,实现了各司其职。

接下来就先实现一个简单的MVP设计模式
1.Model层
在Model层主要就是获取数据然后做数据回调

public interface IModel {
    /**
     * 网络请求加载数据,回调
     */
    void loadData(String appid,DataCallback callback);
    /**
     * 回调接口
     */
    interface DataCallback{
        void complete(String url);
    }
}

2.View层

public interface IBaseView {
    /**
     * 数据显示
     */
    void showData(String url);
}

3.P层
P层主要是实现View层和Model层的绑定,因此需要实例化两个Module。

public class IPresenter {
    private IBaseView mView;
    //在此实例化Model,不需要传入构造方法
    private IModel mModel = new ModelImpl();

    public IPresenter(IBaseView mView) {
        super();
        this.mView = mView;
    }

     /**
     * 实现View和Model的绑定
     * @param appid  View给P层的数据
     */
    public void fetch(String appid){
        if(mModel != null){
            mModel.loadData(appid,new IModel.DataCallback() {
                @Override
                public void complete(String url) {
                    //Model层的数据回调过来,在View层加载
                    mView.showData(url);
                }
            });
        }
    }

}

在上述代码中,没有将Model放在构造方法中的原因就是,如果在Presenter的构造方法中传入Model,那么就得在View层创建Model的实例,这样就会又和Model建立联系,所以在P层做了实现类。

public class ModelImpl implements IModel {
    /**
     * 加载数据
     * @param appid
     * @param callback  回调
     */
    @Override
    public void loadData(String appid, DataCallback callback) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(Constant.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        IDataService dataService = retrofit.create(IDataService.class);
        Call<DataBean> call = dataService.data("getAppConfig.php", appid);
        call.enqueue(new Callback<DataBean>() {
            @Override
            public void onResponse(Call<DataBean> call, Response<DataBean> response) {
                String url = response.body().getUrl();
                //在此将数据回调,到P层
                callback.complete(url);
            }

            @Override
            public void onFailure(Call<DataBean> call, Throwable t) {

            }
        });

    }
}


在Model的实现类ModelImp中,做网络请求操作,将数据回调到P层。

在View层,即可点击获取数据按钮,得到数据的回调。

public class MainActivity extends AppCompatActivity implements IBaseView {
    private IPresenter presenter;
    private EditText et_appid;
    private Button btn_get;
    private TextView tv_data;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //initPresent
        initPresent();
        findView();
        initEvent();
    }

    private void initEvent() {
        btn_get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //点击按钮,就去向P层请求获取数据
                presenter.fetch(getEditText());
            }
        });
    }

    private void findView() {
        et_appid = findViewById(R.id.et_appid);
        btn_get = findViewById(R.id.btn_get);
        tv_data = findViewById(R.id.tv_data);
    }

    private void initPresent() {
        presenter = new IPresenter(this);
    }

    @Override
    public void showData(String url) {
        //url已经在P层获取了M层的回调,这边值需要显示
        tv_data.setText(url);
    }

    public String getEditText(){
        return et_appid.getText().toString();
    }
}

这样就根据输入的appid得到了最终的响应数据。
在这里插入图片描述
目前,以上就是简单地实现了MVP的基础架构,接下来,我们对这个基础架构进行优化。

优化1:内存泄漏

private void initPresent() {
        presenter = new IPresenter(this);
    }

我们在View层使用Presenter的时候,都要去创建一个Presenter实例,因为P和V是一一对应的关系,所以每次创建一个新的View,都需要去创建一个P实例,而且这个P持有View的引用,会造成内存泄漏。

内存泄漏的问题:因为View层和P层是关联的,当View层需要获取数据时,会通过P层去向Model层获取数据;如果当前View退出时,其对应的P层可能还在进行耗时操作,导致View不能退出,导致了内存泄漏。

所以可以创建一个Presenter的基类,当中实现对View的绑定和移除,也就是说,在onCreate的时候,就绑定,在onDestory的时候就移除。

所以先对P和V做一下操作。

public class BasePresenter<V> {
    /**
     * 使用弱引用创建View
     */
    protected WeakReference<V> mView;
    /**
     * 关联View
     */
    public void attachView(V view){
        mView = new WeakReference<>(view);
    }
    /**
     * 解除关联
     */
    public void detachView(V view){
        if(mView != null){
            mView.clear();
        }
    }

    protected V getView(){
        return mView.get();
    }
}


创建一个Activity的基类BaseActivity

public abstract class BaseActivity<V,P extends BasePresenter<V>> extends AppCompatActivity {
    protected P mPresenter;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //创建Presenter,并关联View
        mPresenter = createPresenter();
        mPresenter.attachView((V) this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mPresenter != null){
            mPresenter.detachView((V) this);
            mPresenter = null;
        }
    }

    protected abstract P createPresenter();
}

之前,我们在View层使用Presenter的时候,是使用new 关键字创建出一个Presenter实例化,然后调用fetch方法去将View和Model绑定。在创建的这个BaseActivity中,在onCreate方法中是实例化了这个Presenter,然后绑定了当前的View。

那么在真正的Activity中,去继承这个BaseActivity的时候,就不需要去创建,对于每一个Activity都是这样的。

public class MainActivity extends BaseActivity<IMainView, MainPresenter> implements IMainView {
    private EditText et_appid;
    private Button btn_get;
    private TextView tv_data;

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

    @Override
    protected MainPresenter createPresenter() {
        //在这里已经将Presenter初始化
        return new MainPresenter();
    }

    private void initEvent() {
        btn_get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //点击按钮,就去向P层请求获取数据
                mPresenter.fetch(getEditText());
            }
        });
    }

    private void findView() {
        et_appid = findViewById(R.id.et_appid);
        btn_get = findViewById(R.id.btn_get);
        tv_data = findViewById(R.id.tv_data);
    }


    @Override
    public void showData(String url) {
        //url已经在P层获取了M层的回调,这边值需要显示
        tv_data.setText(url);
    }

    public String getEditText(){
        return et_appid.getText().toString();
    }
}

对于每一个Presenter来说,都不需要再去创建构造方法,直接继承BasePresenter即可。

public class MainPresenter extends BasePresenter<IMainView> {
    //在此实例化Model,不需要传入构造方法
    private IModel mModel = new ModelImpl();
    /**
     * 实现View和Model的绑定
     * @param appid  View给P层的数据
     */
    public void fetch(String appid){
        if(mModel != null){
            mModel.loadData(appid,new IModel.DataCallback() {
                @Override
                public void complete(String url) {
                    //Model层的数据回调过来,在View层加载
                   getView().showData(url);
                }
            });
        }
    }

}

通过这个方法,实现了V和P的绑定,而且不需要去手动new出一个实例,更重要的是解决了内存泄漏的这个问题。
在之后的开发项目中,可以使用这个架构模式进行MVP设计的开发,当然不是一定要用MVP,根据实际的情况去选择合适的设计模式,好了,MVP就先简单介绍到这里,后边还会继续更新。

发布了15 篇原创文章 · 获赞 5 · 访问量 612

猜你喜欢

转载自blog.csdn.net/qq_33235287/article/details/104210276
今日推荐