Android MVC,MVP和MVVM架构模式的探究

本文深入探讨了Android项目开发中,从MVC、MVP到MVVM的框架模式演进,分析了每种模式的设计原理、实现方式及优缺点,强调了数据绑定和LiveData在MVVM中的关键作用。
首语
  • Android项目开发中,尤其大型的项目中,模块内部的高聚合和模块间的低耦合显得很是重要。为此我们需要选择一种框架模式,Android通常使用到的有MVC,MVP和MVVM。通过框架模式设计的项目能够极大提高开发效率,提高项目的可维护性和可扩展性,同时在模块测试和Bug处理上也有很大便利。
需求(查询用户账号信息)
  • 用户输入账号,点击按钮可进行查询账号信息,如果查询数据成功,则将数据展示在页面上;如果查询失败,则在页面上提示获取数据失败。
不使用框架
  • Activity主要实现的功能有获取用户输入的信息、展示获取信息成功页面、展示获取信息失败页面、查询用户数据和业务逻辑。
	//获取用户输入的信息
	private String getUserInput(){
        return etinput.getText().toString().trim();
    }

	//展示获取信息成功页面
    private void showSuccessPage(Account account){
        tvinformation.setText("用户账号:"+account.getName()+"用户等级:"+account.getLevel());
    }

	//展示获取信息失败页面
    private void showFailedPage(){
        tvinformation.setText("获取数据失败");
    }
	
	//查询用户数据
    private void getAccountData(String accountName, MCallBack callBack){
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess){
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callBack.onSuccess(account);
        }else {
            callBack.onFailed();
        }
    }
     @Override
    public void onClick(View view) {
        String userInput = getUserInput();
        getAccountData(userInput, new MCallBack() {
            @Override
            public void onSuccess(Account account) {
                showSuccessPage(account);
            }

            @Override
            public void onFailed() {
                showFailedPage();
            }
        });
    }
    
    public interface MCallBack {

    void onSuccess(Account account);
    void onFailed();
}

	//Account Bean类
	private String name;//姓名
    private int level;//等级

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }
MVC
  • MVC的全名是Model-View-Controller,是模型(Model)-视图(View)-控制器(Controller)的缩写。Model层负责数据处理(网络请求,SQL等),View层负责Layout、View控件。Controller层负责Activity,Fragment。
需求分析
  • Controller层:业务逻辑处理,获取用户输入,展示成功页面,展示失败页面。
  • Model层:查询账号数据。
  • View层:layout布局。
实现
  • 1.将数据的获取与界面的展示分离 。
  • 2.解决各层之间通信问题(Activity通知Model获取数据,Model通知Activity更新页面)。
//Model层
public void getAccountData(String accountName, MCallBack callBack){
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess){
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callBack.onSuccess(account);
        }else {
            callBack.onFailed();
        }
    }
//Controller层
	private String getUserInput(){
        return etinput.getText().toString().trim();
    }
    private void showSuccessPage(Account account){
        tvinformation.setText("用户账号:"+account.getName()+"用户等级:"+account.getLevel());
    }

    private void showFailedPage(){
        tvinformation.setText("获取数据失败");
    }
    @Override
    public void onClick(View view) {
       mMvcModel.getAccountData(getUserInput(), new MCallBack() {
           @Override
           public void onSuccess(Account account) {
               showSuccessPage(account);
           }

           @Override
           public void onFailed() {
               showFailedPage();
           }
       });
    }    
MVC优缺点
  • 优点:一定程度上实现了Model与View的分离,降低了代码的耦合性。
  • 缺点:Controller与View难以完全解耦,并且随着项目复杂度的提升,Controller将越来越臃肿。
MVP
  • MVP的全名是Model-View-Presenter,是模型(Model)-视图(View)-中间层(Presenter)的缩写。Model层负责数据处理(网络请求、SQL等) ,View层负责用户交互(Activity,Fragment),Presenter层作为View层与Model层中间的纽带,负责处理与用户交互的主要业务逻辑。
需求分析
  • Model层:查询账号数据。
  • View层:获取用户输入、展示成功界面、展示失败界面。
  • Presenter层:业务逻辑处理。
实现
  • 1.Activity负责提供View层面的功能(采用实现接口的方式)
  • 2.Model层负责提供数据方面的功能。
  • Model层与View层不再直接通信,通过Presenter来实现。
//Model层负责提供数据方面的功能
public void getAccountData(String accountName, MCallBack callBack){
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess){
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callBack.onSuccess(account);
        }else {
            callBack.onFailed();
        }
    }
//采用实现接口的方式实现View层面的功能
    public interface MVPView {

    String getUserInput();
    void showSuccessPage(Account account);
    void showFailedPage();
}
//中间层Presenter
private MVPView mMVPView;
    private MVPModel mMVPModel;

    public MVPPresenter(MVPView mMVPView) {
        this.mMVPView = mMVPView;
        mMVPModel = new MVPModel();
    }
    public void getData(String accountName){
        mMVPModel.getAccountData(accountName, new MCallBack() {
            @Override
            public void onSuccess(Account account) {
                mMVPView.showSuccessPage(account);
            }

            @Override
            public void onFailed() {
                mMVPView.showFailedPage();
            }
        });
    }
//Activity中Model与View不再直接通信,通过Presenter来实现。继承View接口层   
	@Override
    public void onClick(View view) {
        mMVPPresenter.getData(getUserInput());
    }

    @Override
    public String getUserInput() {
        return etinput.getText().toString().trim();
    }

    @Override
    public void showSuccessPage(Account account) {
        tvinformation.setText("用户账号:"+account.getName()+"用户等级:"+account.getLevel());
    }

    @Override
    public void showFailedPage() {
        tvinformation.setText("获取数据失败");
    }
MVP优缺点
  • 优点:解决了MVC中Controller与View过度耦合的的缺点,职责划分明显,更加易于维护。
  • 缺点:接口数量多,项目复杂度提高,随着项目复杂度的提高,Presenter将越来越臃肿。
建议
  • 1.接口规范化(封装父类接口以减少接口的使用量)。

  • 2.使用MVP插件自动生成MVP的代码。

  • 3.对于一些简单的页面,可以选择不使用框架。

  • 4.根据项目复杂度,部分模块可以选择不使用接口。

MVC与MVP的区别
  • 1.Model与View不再直接进行通信,而是通过中间层Presenter来实现。
  • 2.Activity的功能被简化,不再充当控制器,主要负责View层面的工作。
PS(常见MVP插件)
MVVM
  • MVVM的全名是Model-View-ViewModel,是模型(Model)-视图(View)-数据视图管理器(ViewModel)的缩写。Model层负责数据处理,View层负责Activity,Fragment。VIewModel层负责调用Model,拿到数据更新自身,而View与ViewModel双向绑定,所以View会自动更新。MVVM在MVP的基础上实现了数据视图的绑定(DataBinding),当数据变化时,视图会自动更新;反之,视图发生变化时,数据也会自动更新。
DataBinding
使用步骤

1.启用DataBinding

//编辑app目录下的build.gradle文件,添加下面的内容。
android {
    ...
    dataBinding {
        enabled = true
    }
}

2.修改布局文件为DataBinding布局

  • 选中布局文件根布局(如LinearLayout),按alt+enter,点击Convert to data binding layout,
    布局文件转化为DataBinding布局。它最外层是layout,里面包含data和我们的原始布局。
  • 在data中我们可以声明对象,然后我们就可以在布局文件中使用对象。@={}表示双向绑定(具体见代码)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="account"
            type="com.yhj.framedemo.bean.Account" />

        <variable
            name="activity"
            type="android.app.Activity" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".databinding.DemoActivity">

        <TextView
            android:id="@+id/tv_level"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="80dp"
            android:text="@{account.name+'|'+account.level}" />

        <Button
            android:id="@+id/bt_level"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="80dp"
            android:onClick="@{activity.onClick()}"
            android:text="等级+1" />

    </LinearLayout>
</layout>
  • 生成DataBinding布局以后,setContentView(view)也要发生改变,使用DataBindingUtil.setContentView,同时使用binding省略了findViewById。
  ActivityMvvmBinding binding = 
  DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
  binding.etInput.setText("省略findViewById()");

3.数据绑定

  • 让Bean类Account继承BaseObservable,为了使数据发生变化视图自动更新,在getLevel()上加注解Binable,在setLevel()中notifyPropertyChanged(BR.level)。
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_demo);
        account = new Account();
        account.setName("Tom");
        account.setLevel(100);
        binding.setAccount(account);
        binding.setActivity(this);
    }

    public void onClick(View view){
        Toast.makeText(this, "点击了!", Toast.LENGTH_SHORT).show();
        int level = account.getLevel();
        account.setLevel(level+1);
	    //binding.setAccount(account);
    }
public class Account extends BaseObservable {

    private String name;//姓名
    private int level;//等级
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Bindable
    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
        notifyPropertyChanged(BR.level);
    }
}
需求分析
  • Model层:查询账号数据。
  • View层:获取用户输入,展示成功界面,展示失败界面。
  • ViewModel层:业务逻辑处理,数据更新。
实现
  • 提供View,ViewModel以及Model三层。
  • 将布局修改为DataBinding布局
  • View与ViewModel之间通过DataBinding进行通信。
  • 获取数据展示在界面上。
<?xml version="1.0" encoding="utf-8"?>
    <!--    首先是DataBinding布局-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewModel"
            type="com.yhj.framedemo.mvvm.MVVMViewModel"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".mvvm.MVVMActivity">

        <EditText
            android:hint="请输入要查询的账号"
            android:text="@={viewModel.userInput}"
            android:layout_marginTop="20dp"
            android:id="@+id/et_input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <Button
            android:layout_gravity="center"
            android:layout_marginTop="80dp"
            android:id="@+id/bt_get"
            android:onClick="@{viewModel.getData}"
            android:text="获取账号信息"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:layout_gravity="center"
            android:layout_marginTop="80dp"
            android:id="@+id/tv_information"
            android:text="@{viewModel.result}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</layout>
//Model层数据处理
public void getAccountData(String accountName, MCallBack callBack){
        Random random = new Random();
        boolean isSuccess = random.nextBoolean();
        if (isSuccess){
            Account account = new Account();
            account.setName(accountName);
            account.setLevel(100);
            callBack.onSuccess(account);
        }else {
            callBack.onFailed();
        }

    }
//ViewModel层
public class MVVMViewModel extends BaseObservable {
    private String result;
    private String userInput;

    @Bindable
    public String getUserInput() {
        return userInput;
    }

    public void setUserInput(String userInput) {
        this.userInput = userInput;
        notifyPropertyChanged(BR.userInput);
    }

    private final MVVMModel mvvmModel;
    private MVVMModel mvvmModel1;
    private ActivityMvvmBinding binding;

    @Bindable
    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
        notifyPropertyChanged(BR.result);
    }

    //一般需要传入Application对象,方便在ViewModel中使用Application
    //比如SharedPreference
    public MVVMViewModel(Application application) {
        mvvmModel = new MVVMModel();
    }

    public void getData(View view) {
        mvvmModel.getAccountData(userInput, new MCallBack() {
            @Override
            public void onSuccess(Account account) {
                String info = account.getName() + "|" + account.getLevel();
                setResult(info);
            }

            @Override
            public void onFailed() {
                setResult("获取失败!!!");
            }
        });
    }
}
//View层Activity
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMvvmBinding binding =
                DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
        MVVMViewModel mvvmViewModel = new MVVMViewModel(getApplication());

        binding.setViewModel(mvvmViewModel);

    }
  • View可以向ViewModel传递信息,ViewModel改变数据通知View自动更新,但是有些功能我们要在Activity中实现(比如点击按钮获取应用权限),ViewModel如何通知View呢?要实现这个功能,我们可以让ViewModel执有Activity的引用,或者借用EventBus。对于MVVM模式来说,我们可以使用LiveData+ViewModel来实现。
LiveData
MVVM优缺点
  • 优点:实现了数据与视图的双向绑定,极大的简化代码。
  • 缺点:bug难以调试,并且DataBinding目前还存在一些编译问题。
总结
  • Android开发中,一直在用MVC框架,甚至可以说没有使用框架,一些大型项目随着不断的迭代,出现了许多问题,推出了MVP框架,再到现在主推的MVVM框架。架构演进代码质量也更高,但学习难度也增大。
  • Android开发语言,一直在用Java,如今推出了Kotlin语言已经成为Android官方支持开发语言。以及跨平台开发方案Flutter使用的Dart语言,想想哇,Android之路漫漫啊,还有许多东西要学习使用。需要一直提升自己,做未来的T型人才
  • 项目源码:FrameDemo
内容概要:本文介绍了一个基于多传感器融合的定位系统设计方案,采用GPS、里程计电子罗盘作为定位传感器,利用扩展卡尔曼滤波(EKF)算法对多源传感器数据进行融合处理,最终输出目标的滤波后位置信息,并提供了完整的Matlab代码实现。该方法有效提升了定位精度与稳定性,尤其适用于存在单一传感器误差或信号丢失的复杂环境,如自动驾驶、移动采用GPS、里程计电子罗盘作为定位传感器,EKF作为多传感器的融合算法,最终输出目标的滤波位置(Matlab代码实现)机器人导航等领域。文中详细阐述了各传感器的数据建模方式、状态转移与观测方程构建,以及EKF算法的具体实现步骤,具有较强的工程实践价值。; 适合人群:具备一定Matlab编程基础,熟悉传感器原理滤波算法的高校研究生、科研人员及从事自动驾驶、机器人导航等相关领域的工程技术人员。; 使用场景及目标:①学习掌握多传感器融合的基本理论与实现方法;②应用于移动机器人、无人车、无人机等系统的高精度定位与导航开发;③作为EKF算法在实际工程中应用的教学案例或项目参考; 阅读建议:建议读者结合Matlab代码逐行理解算法实现过程,重点关注状态预测与观测更新模块的设计逻辑,可尝试引入真实传感器数据或仿真噪声环境以验证算法鲁棒性,并进一步拓展至UKF、PF等更高级滤波算法的研究与对比。
内容概要:文章围绕智能汽车新一代传感器的发展趋势,重点阐述了BEV(鸟瞰图视角)端到端感知融合架构如何成为智能驾驶感知系统的新范式。传统后融合与前融合方案因信息丢失或算力需求过高难以满足高阶智驾需求,而基于Transformer的BEV融合方案通过统一坐标系下的多源传感器特征融合,在保证感知精度的同时兼顾算力可行性,显著提升复杂场景下的鲁棒性与系统可靠性。此外,文章指出BEV模型落地面临大算力依赖与高数据成本的挑战,提出“数据采集-模型训练-算法迭代-数据反哺”的高效数据闭环体系,通过自动化标注与长尾数据反馈实现算法持续进化,降低对人工标注的依赖,提升数据利用效率。典型企业案例进一步验证了该路径的技术可行性与经济价值。; 适合人群:从事汽车电子、智能驾驶感知算法研发的工程师,以及关注自动驾驶技术趋势的产品经理技术管理者;具备一定自动驾驶基础知识,希望深入了解BEV架构与数据闭环机制的专业人士。; 使用场景及目标:①理解BEV+Transformer为何成为当前感知融合的主流技术路线;②掌握数据闭环在BEV模型迭代中的关键作用及其工程实现逻辑;③为智能驾驶系统架构设计、传感器选型与算法优化提供决策参考; 阅读建议:本文侧重技术趋势分析与系统级思考,建议结合实际项目背景阅读,重点关注BEV融合逻辑与数据闭环构建方法,并可延伸研究相关企业在舱泊一体等场景的应用实践。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八归少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值