MVX Android设计架构浅析-MVP

本文深入解析MVP架构在Android应用开发中的优势,从交互简化、耦合度降低、易于测试和维护等方面阐述其价值,并通过代码示例详细展示了如何将MVP模式应用于实际项目中,包括接口定义、实现类编写及生命周期管理,特别关注了Activity重启问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

###简介
MVX Android设计架构浅析-MVC 读过这篇文章以后,应该对MVC框架有个大概的了解,这也是大部分Android应该的常用框架,但是这种框架给人的感觉更像是 View-Module框架,因为View层的确没有显现出来,而且View和Module的耦合度较高,到最后会像下图一样,业务逻辑和View展现紧密耦合在一起,相互交错,随着项目的壮大以后很难维护。

此处输入图片的描述

这么复杂的交互基本集中在Activity或者Fragment中,这样Controller每一部分都不能重复利用,无法轻易的测试、或者调试和重构。

如果使用MVP,那会是什么画面?
此处输入图片的描述

复杂的任务被分成细小的任务,并且很容易解决。越小的东西,bug越少,越容易debug,更好测试。在MVP模式下的View层将会变得简单,所以即便是他请求数据的时候也不需要回调函数。View逻辑变成十分直接。

###简化的交互图
经过上面的表述,我们体验到MVP的优势,所以这样有必要再温习一下MVP的交互图
此处输入图片的描述

###代码
Talk is cheap,show me the code.(废话少说,直接上代码)

读过MVX Android设计架构浅析-MVC这篇文章的同学都应该还记得,在层与层之间衔接最好是通过接口,所以我们不妨直接先定义接口

####接口
View层(不仅仅局限于Android中的View,还有其他与用户交互的构件)

public interface WeatherView {
    void showLoading();

    void hideLoading();

    void showError();

    void setWeatherInfo(Weather weather);
}

这个接口也清晰的说明了View层可以操作的方法和具有的功能

Module层(抽象数据层)

public interface WeatherModel {
    void loadWeather(String cityNO, OnWeatherListener listener);
}

这个接口比较简单,就是单一的获取Remote/Local数据

Presenter层(主要的业务逻辑层)

public interface WeatherPresenter {
    void getWeather(String cityNO);
}

这个接口主要是处理业务逻辑,完成中间的View和Module的桥接。

####实现
View层(不仅仅局限于Android中的View,还有其他与用户交互的构件)

public class WeatherActivity extends BaseActivity implements WeatherView, View.OnClickListener {
    private Dialog loadingDialog;
    private EditText cityNOInput;
    private TextView city;
    private TextView cityNO;
    private TextView temp;
    private TextView wd;
    private TextView ws;
    private TextView sd;
    private TextView wse;
    private TextView time;
    private TextView njd;

    private WeatherPresenter weatherPresenter;

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

    }

    private void init() {
        cityNOInput = findView(R.id.et_city_no);
        city = findView(R.id.tv_city);
        cityNO = findView(R.id.tv_city_no);
        temp = findView(R.id.tv_temp);
        wd = findView(R.id.tv_WD);
        ws = findView(R.id.tv_WS);
        sd = findView(R.id.tv_SD);
        wse = findView(R.id.tv_WSE);
        time = findView(R.id.tv_time);
        njd = findView(R.id.tv_njd);

        findView(R.id.btn_go).setOnClickListener(this);

        weatherPresenter = new WeatherPresenterImpl(this); //传入WeatherView
        loadingDialog = new ProgressDialog(this);
        loadingDialog.setTitle("加载天气中...");
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_go:
                weatherPresenter.getWeather(cityNOInput.getText().toString().trim());
                break;
        }
    }


    @Override
    public void showLoading() {
        loadingDialog.show();
    }

    @Override
    public void hideLoading() {
        loadingDialog.dismiss();
    }

    @Override
    public void showError() {
        //Do something
        Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void setWeatherInfo(Weather weather) {
        WeatherInfo info = weather.getWeatherinfo();
        city.setText(info.getCity());
        cityNO.setText(info.getCityid());
        temp.setText(info.getTemp());
        wd.setText(info.getWD());
        ws.setText(info.getWS());
        sd.setText(info.getSD());
        wse.setText(info.getWS());
        time.setText(info.getTemp());
        njd.setText(info.getNjd());
    }

}

View成的实现类,里面没有设计任何业务逻辑,L14 可以看出View持有WeatherPresenter的实例。而L38weatherPresenter = new WeatherPresenterImpl(this)又可以看出WeatherPresenter同样会持有View的引用。所以ViewPresenter之间是紧耦合。不过这里都是通过接口来减轻这种耦合度,并且有利于以后的代码维护。

Module层(抽象数据层)

public class WeatherModelImpl implements WeatherModel {
    @Override
    public void loadWeather(String cityNO, final OnWeatherListener listener) {
        /*数据层操作*/
        VolleyRequest.newInstance().newGsonRequest("http://www.weather.com.cn/data/sk/" + cityNO + ".html",
            Weather.class, new Response.Listener<Weather>() {
                @Override
                public void onResponse(Weather weather) {
                    if (weather != null) {
                        listener.onSuccess(weather);
                    } else {
                        listener.onError();
                    }
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    listener.onError();
                }
            });
    }
}

Module实现类比较单一,就是获取Remote/Local数据,还有一些数据解析和数据封装操作也可以通过这层去实现,另外Android是UI线程非安全的,所以如果通过子线程获取Remote/Local数据,那么更新UI的操作必然不能直接进行,只能通过主线程去更新UI,所以这里讲Module和View分层也是很有道理的。

Presenter层(主要的业务逻辑层)

public class WeatherPresenterImpl implements WeatherPresenter, OnWeatherListener {
	/*Presenter作为中间层,持有View和Model的引用*/
	private WeatherView weatherView;
	private WeatherModel weatherModel;

	public WeatherPresenterImpl(WeatherView weatherView) {
		this.weatherView = weatherView;
		weatherModel = new WeatherModelImpl();
	}

	@Override
	public void getWeather(String cityNO) {
		weatherView.showLoading();
		weatherModel.loadWeather(cityNO, this);
	}

	@Override
	public void onSuccess(Weather weather) {
		weatherView.hideLoading();
		weatherView.setWeatherInfo(weather);
	}

	@Override
	public void onError() {
		weatherView.hideLoading();
		weatherView.showError();
	}
}

通过这个Presenter类可以看到仅仅有业务逻辑,而不会有UI和数据先关的东西在里面。同时也可以看出,这个类更多的是在桥接ViewModule层,并没有做其他多余的操作。另外Module层通过回调到Presenter,然后通过Presenter通知View层更新UI,这个回调就是上面的OnWeatherListener,当然如果想让这种耦合关系变得极其简单,可以通过EventBus处理。

前面说了很多MVP的好话,这里不得不给他破一点凉水,实际开发过程中会有个不大不小的坑。

Activity会在很多情况下被系统重启:
- 当用户旋转屏幕
- 在后台时内存不足
- 改变语言设置
- attache 一个外部显示器等。

一旦重启以后,Presenter如何处理成为一个问题,大体的处理思路如下图所示
此处输入图片的描述

前两种就不细说了,关于第三种处理方案可以详细参考 通过Loader延长Presenter生命周期

另外本文参考了 Android MVP 详解(上) 该文总结的很逆天,再次佩服作者的无私奉献精神。

附:
MVX Android设计架构浅析
MVX Android设计架构浅析-MVC
MVX Android设计架构浅析-MVP
MVX Android设计架构浅析-MVVM

### MVX-Net 架构概述 MVX-Net是一种用于3D对象检测的多模态网络框架,旨在通过融合不同传感器的数据来提高3D物体识别的效果[^1]。该方法特别适用于自动驾驶场景中的障碍物检测。 #### 多模态数据处理 MVX-Net能够接收来自激光雷达(LiDAR)点云和摄像头图像两种类型的输入,并利用这些互补的信息源提升最终的检测精度。对于LiDAR数据,采用体素化技术将其转换成三维网格;而对于相机捕捉到的画面,则提取二维特征图作为补充信息的一部分[^4]。 #### 主要组件构成 整个系统由以下几个核心部分组成: - **Voxel Feature Encoding (VFE)** 层:负责将原始点云转化为具有语义意义的高维向量表示; - **Region Proposal Network (RPN)** :基于编码后的特征生成候选区域建议; - **Multi-modal Fusion Module** : 结合视觉线索与几何形状特性完成更精准的目标定位分类任务。 ```python class MultiModalFusion(nn.Module): def __init__(self, input_channels=256): super(MultiModalFusion, self).__init__() # 定义卷积层和其他必要的操作 def forward(self, voxel_features, image_features): fused_output = torch.cat((voxel_features, image_features), dim=1) return fused_output ``` ### 应用场景分析 在实际应用方面,MVX-net非常适合那些需要精确感知周围环境并做出快速反应的任务领域: - 自动驾驶汽车可以依靠此算法更好地理解复杂的交通状况; - 物流机器人能够在仓库环境中高效地搬运货物而不发生碰撞事故 ; - 智能安防监控设备借助它实现全天候无死角的安全防护功能. 综上所述,MVX-net不仅代表了一种先进的计算机视觉解决方案,也为众多行业带来了巨大的变革潜力.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值