mvc与mvp

mvc

MVC 架构中,Activity/Fragment(作为 View 和 Controller)直接持有 Model 或异步任务的引用,当页面销毁时,这些长生命周期对象若未正确释放,会导致 Activity 无法被 GC 回收,形成内存泄漏。

举例:

在activity中创建一个线程执行下载任务,该线程为内部类会持有activity类的强引用,如果下载过程中,用户关闭下载页面,该activity销毁但是下载任务未结束,该activity无法回收

java 复制代码
// MVC模式下的Activity(同时作为View和Controller)
public class HomeActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        
        // 错误示例:AsyncTask内部类隐式持有Activity引用
        new DownloadTask().execute("url");
    }
    
    // 内部类会隐式持有外部类(Activity)的强引用
    private class DownloadTask extends AsyncTask<String, Void, byte[]> {
        @Override
        protected byte[] doInBackground(String... params) {
            // 网络请求,耗时操作
            return downloadData(params[0]);
        }
        
        @Override
        protected void onPostExecute(byte[] result) {
            // 更新UI(View层操作)
            TextView textView = findViewById(R.id.result_text);
            textView.setText("下载完成");
        }
    }
    
    // 页面销毁时,若AsyncTask未完成,Activity无法被回收
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 未取消任务,泄漏风险
    }
}

mvp

**对比mvc:

把原来的UI逻辑抽象成View接口,把原来的业务逻辑抽象成Presenter接口,model还是原来的model

基本业务逻辑示例

示例

view: 定义展示的方法,依赖具体的activity实现

java 复制代码
//顶层接口
public interface IBaseVeiw {
    void showErrorMesage(String msg);
}


public interface IGoodsView extends IBaseVeiw{
    void showGoodView(List<Goods> goods);
}

model:存储和获取数据的逻辑,与view没有直接联系

java 复制代码
//顶层接口
public interface IGoodsModel {
    void loadGoodsData(OnLoadlistener onLoadListener);
    interface OnLoadlistener{
        void onComplete(List<Goods> goods);
        void onError(String msg);
    }
}


//业务相关具体实现类
public class GoodsModel implements IGoodsModel{
    @Override
    public void loadGoodsData(OnLoadlistener onLoadListener) {
        onLoadListener.onComplete(getData());
    }

    //数据应来自真实情况(网络,数据库..  )
    private List<Goods> getData() {
        ArrayList data = new ArrayList<>();
        for(int i=0;i<10;i++){
           data.add(new Goods("商品"+i,i));
        }
        return data;
    }

}

presenter:获取view和model,将model的获取的数据用view的方法显示

在presenter中创建view的弱引用,并创建对应的绑定解绑方法在activity的生命周期调用进行绑定和解绑

java 复制代码
public class GoodsPresenter<T extends IBaseVeiw>  {
    //IGoodsView iGoodsView;
    public WeakReference<T> iGoodsView;
    IGoodsModel iGoodsModel = new GoodsModel();

    /*
       绑定
     */
    public void attachView(T view){
        iGoodsView = new WeakReference<>(view);
    }

    /*
    解除绑定
     */
    public void deatchView(){
        if(iGoodsView!=null){
            iGoodsView.clear();
            iGoodsView = null;
        }
    }

    public void  fetch(){
        if(iGoodsView.get()!=null&&iGoodsModel!=null){
            iGoodsModel.loadGoodsData(new IGoodsModel.OnLoadlistener() {
                @Override
                public void onComplete(List<Goods> goods) {
                    ((IGoodsView)iGoodsView.get()).showGoodView(goods);
                }

                @Override
                public void onError(String msg) {
                }
            });
        }
    }
}

在activity中使用presenter,只关心两件事,数据从哪里来,表示层选择什么

java 复制代码
public class MainActivity extends AppCompatActivity implements IGoodsView {
    private ActivityMainBinding binding;
    private MainAdapter mainAdapter;
    private GoodsPresenter goodsPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        mainAdapter = new MainAdapter(R.layout.item_book);

        goodsPresenter = new GoodsPresenter();
        //使用弱引用
        goodsPresenter.attachView(this);
        goodsPresenter.fetch();
    }

    @Override
    public void showErrorMesage(String msg) {
    }

    @Override
    public void showGoodView(List<Goods> goods) {
        mainAdapter.setNewInstance(goods);
        binding.rec.setAdapter(mainAdapter);
    }

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