Android 架构模式

MVC

MVC是 Model-View-Controller 的简称。

  • M:模型层(Model) 负责与数据库和网络层通信,并获取和存储应用的数据;
  • V:视图层(View) 负责将 Model 层的数据做可视化的处理,同时处理与用户的交互;
  • C:控制层(Controller) 用于建立Model层与View层的联系,负责处理主要的业务逻辑,并根据用户操作更新 Model 层数据。

在 Android 项目的 MVC 架构中由于 Activity 同时充当了 View 层与 Controller 层两个角色,所以 Android 中的 MVC 更像下面的这种结构:

Model层

LogingListener是一个接口:

  public interface LoginListener {
    void onSuccess(User data);

    void onFailed(String msg);
}
public class LoginModel {
    public void login(String username, String password, LoginListener listener) {
        RetrofitManager.getApiService()
                .login(username, password)
                .enqueue(new Callback<User>() {
                    @Override
                    public void onResponse(Call<User> call, Response<User> response) {
                        listener.onSuccess(response.data);
                    }

                    @Override
                    public void onFailed(Exception e) {
                        listener.onFailed(e.getMessage());
                    }
                });
        
    }
}

Controller/View层 

public class MainActivity extends AppCompactActivity implements LoginListener {

    private LoginModel loginModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        model = new LoginModel();
        findViewbyId(R.id.btn_fetch_data).setOnClickListener(view -> {
                    String username = findViewById(R.id.et_username).getText().toString();
                    String password = findViewById(R.id.et_password).getText().toString();
                    loginModel.login(username, password, this);
                }
        );
    }

    @Override
    public void onSuccess(User data) {
        // Update UI
    }

    @Override
    public void onFailed(String msg) {
        // Update UI
    }
}

不足: 

  • Android中的MVC代码对于分层并不明确,导致了Controller层与View层混为一体。
  • Model 层与 View 层存在耦合,存在相互依赖关系。
  • 开发时不注重分层,Model层代码也被塞进了Activity/Fragment,使得代码层次更加混乱。

MVP

针对以上MVC架构中存在的问题,我们可以在MVC的基础上进行优化解决。

  • 即从Activity中剥离出控制层的逻辑,并阻断Model层与View层的耦合。
  • Model层不直接与View通信,而是在数据改变时让 Model通知控制控制层,控制层再通知View层去做界面更新,这就是MVP的架构思想。
  • M:模型层(Model) 与MVC中的一致,同样是负责与数据库和网络层通信,并获取和存储应用的数据,区别在于Model层不再与View层直接通信,而是与Presenter层通信。
  • V:视图层(View) 负责将 Model 层的数据做可视化的处理,同时与Presenter层交互。跟MVC相比,MVP的View层与Model层不再耦合。
  • P:控制层(Presenter) 主要负责处理业务逻辑,并监听Model层数据改变,然后调用View层刷新UI。

MVP 的结构图如下图所示: 

 

从上图中可以看出:

  • View直接与Presenter层通信,当View层接收到用户操作后会调用 Presenter层去处理业务逻辑。
  • Presenter层通过Model去获取数据,Model层获取到数据后又将最新的数据传回 Presenter。
  • 而Presenter层又持有View层的引用,进而将数据传给View层进行展示。

Model层

LogingListener是一个接口:

  public interface LoginListener {
    void onSuccess(User data);

    void onFailed(String msg);
}
public class LoginModel {
    public void login(String username, String password, LoginListener listener) {
        RetrofitManager.getApiService()
                .login(username, password)
                .enqueue(new Callback<User>() {
                    @Override
                    public void onResponse(Call<User> call, Response<User> response) {
                        listener.onSuccess(response.data);
                    }

                    @Override
                    public void onFailed(Exception e) {
                        listener.onFailed(e.getMessage());
                    }
                });
        
    }
}

Presenter 层代码

  • 由于 Presenter 需要通知 View 层更新UI,因此需要持有View。
  • Presenter也需要与Model层通信,因此Presenter层也会持有Model层。
  • 在用户触发登录操作后,调用Presenter的登录逻辑,Presenter通过Model进行登录操作,根据登录结果反馈给View层做不同的更新操作。

此时可将,view中的更新方法抽象出一个 View 接口 ,在View中实现这个接口。

public interface ILoginView {
    void showLoading();

    void dismissLoading();

    void loginSuccess(User data);

    void loginFailer(String errorMsg);
}
public class LoginPresenter {

    // Model 层 
    private LoginModel model;

    // View 层 
    private ILoginView view;

    public LoginPresenter(LoginView view) {
        this.model = new LoginModel();
        this.view = view;
    }

    public void login(String username, String password) {
        view.showLoading();
        model.login(username, password, new LoginListener() {
            @Override
            public void onSuccess(User user) {
                view.loginSuccess(user);
                view.dismissLoading();
            }

            @Override
            public void onFailed(String msg) {
                view.loginFailer(msg);
                view.dismissLoading();
            }
        });
    }

    @Override
    public void onDestory() {
        // recycle instance.
    }
}

View 层代码

  • 在View中实现更新View的接口
  • 在View中持有Presenter来处理业务逻辑
public class MainActivity extends AppCompatActivity implements ILoginView {

    private LoginPresenter presenter;

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

        presenter = new LoginPresenter(this);
        findViewById(R.id.button).setOnClickListener(v -> {
            String username = findViewById(R.id.et_username).getText().toString();
            String password = findViewById(R.id.et_password).getText().toString();
            presenter.login(username, password);
        });
    }

    @Override
    public void loginSuccess(User user) {
        // Update UI.
    }

    @Override
    public void loginFailer(String msg) {
        // Update UI.
    }

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

    @Override
    public void showLoading() {

    }

    @Override
    public void dismissLoading() {
    }
}

MVP的本质是面向接口编程,实现依赖倒置原则。可以看得出来MVP架构在分层上相比 MVC更加清晰明确,且解耦了Model层与View层。但MVP也存在一些弊端。

不足:

  • 引入大量的 IView、IPresenter接口实现类,增加项目的复杂度。
  • View 层与 Presenter 相互持有,存在耦合。

MVVM

MVVM是 ** Model-View-ViewModel** 的简称。

  • M:模型层(Model) 与MVP中的Model层一致,负责与数据库和网络层通信,获取并存储数据。与MVP的区别在于Model层不再通过回调通知业务逻辑层数据改变,而是通过观察者模式实现。
  • V:视图(View) 负责将Model层的数据做可视化的处理,同时与ViewModel层交互。
  • VM:视图模型(ViewModel) 主要负责业务逻辑的处理,同时与 Model 层 和 View层交互。与MVP的Presenter相比,ViewModel不再依赖View,使得解耦更加彻底。

 

MVVM架构的本质是数据驱动,它的最大的特点是单向依赖。MVVM架构通过观察者模式让ViewModel与View解耦,实现了View依赖ViewModel,ViewModel依赖Model的单向依赖。

观察者模式

自定义观察者

  • 实现观察者接口
public interface Observer<T> {
    // 成功的回调
    void onSuccess(T data);

    // 失败的回调
    void onFailed(String msg);
}
  • 抽象被观察者
public abstract class Observable<T> {
    // 注册观察者
    void register(Observer observer);

    // 取消注册
    void unregister(Observer observer);

    // 数据改变(设置成功数据)
    protected void setValue(T data) {

    }

    // 失败,设置失败原因
    void onFailed(String msg);
}
  • 被观察者具体实现
public class LoginObservable implements Observable<User> {

    private final List<Observer<User>> list = new ArrayList<>();

    private User user;

    @Override
    public void register(Observer<User> observer) {
        list.add(observer);
    }

    @Override
    public void unregister(Observer<User> observer) {
        liset.remove(observer);
    }

    @Override
    public void setValue(User user) {
        this.user = user;
        for (Observer observer : list) {
            observer.onSuccess(user);
        }
    }

    @Override
    public void onFailed(String msg) {
        for (Observer observer : list) {
            observer.onFailed(msg);
        }
    }
}

Model层

Model层最大的特点是被赋予了数据获取的职责,与我们平常Model层只定义实体对象的行为截然不同。

实例中,数据的获取、存储、数据状态变化都是Model层的任务。Model包括实体模型(Bean)、Retrofit的Service ,获取网络数据接口,本地存储(增删改查)接口,数据变化监听等。

Model提供数据获取接口供ViewModel调用,经数据转换和操作并最终映射绑定到View层某个UI元素的属性上。

public class LoginModel {
    public void login(String username, String password, LoginObservable observable) {
        RetrofitManager.getApiService()
                .login(username, password)
                .enqueue(new Callback<User>() {
                    @Override
                    public void onResponse(Call<User> call, Response<User> response) {
                        observable.setValue(response.data);
                    }

                    @Override
                    public void onFailed(Exception e) {
                        observable.onFailed(e.getMessage());
                    }
                });
    }
}

ViewModel层

ViewModel层需要持有Model层,并且ViewModel层持有一个LoginObservable,并开放一个getObservable的方法供View层使用。

public class LoginViewModel {

    private LoginObservable observable;

    private LoginModel loginModel;

    public LoginViewModel() {
        loginModel = new LoginModel();
        observable = new LoginObservable();
    }

    public void login(String username, String password) {
        loginModel.login(username, password, observable);
    }

    // 这里返回值是父类Observable,即View层得到的Observable无法调用setValue
    public Observable getObservable() {
        return observable;
    }
}

View层

View层持有ViewModel,用户触发登录事件通过View层交给Model处理,Model层在登录成后将数据交给ViewModel中的观察者。

因此,View层只需要获取到ViewModel层的观察者并观察到数据改变后更新UI即可。

public class MainActivity extends AppCompatActivity implements Observer<User> {

    private LoginViewModel viewModel;

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

        viewModel = new LoginViewModel();
        viewModel.getObservable().register(this);
        findViewById(R.id.button).setOnClickListener(v -> {
            String username = findViewById(R.id.et_username).getText().toString();
            String password = findViewById(R.id.et_password).getText().toString();
            viewModel.login(username, password);
        });
    }

    @Override
    public void onDestroy() {
        super.onDestory();
        viewModel.getObservable().unregister(this);
    }

    @Override
    public void onSuccess(User user) {
        // fetch data success,update UI.
    }

    @Override
    public void onFailed(String message) {
        // fetch data failed,update UI.
    }
}

Jetpack组件实现 MVVM模式

为了实现MVVM架构,Google提供了一套强大的Jetpack组件,包括LiveData、ViewModel和Data Binding等。这些组件可以帮助开发人员更轻松地实现MVVM架构,并提供了许多现代化的开发工具和技术。

LiveData

Android --- LiveData-CSDN博客

DataBinding

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/745358.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

图片裁剪怎么弄?裁剪图片的四种极为简单的方法

图片裁剪怎么弄&#xff1f;裁剪图片是在编辑和美化图片时常见的操作&#xff0c;它可以帮助你去除不需要的部分&#xff0c;突出重点内容&#xff0c;或者改变图片的外观和比例。这个过程既简单又具有很大的创意空间&#xff0c;因此&#xff0c;掌握如何裁剪图片是提升你图像…

Verilog刷题笔记49——Fsm1同步复位

题目&#xff1a; 解题&#xff1a; module top_module(clk,reset,in,out);input clk;input reset;input in;output out;parameter A0,B1;reg [1:0]current_state,next_state;always(posedge clk)beginif(reset)current_stateB;elsecurrent_statenext_state;endalways(*)beg…

AI绘画Stable diffusion的SDXL模型超详细讲解,针不错!(含实操教程)

大家好&#xff0c;我是画画的小强 朋友们好&#xff0c;今天分享的是Stable diffusion的SDXL模型以及相关实操。 与之前的SD1.5大模型不同&#xff0c;这次的SDXL在架构上采用了“两步走”的生图方式&#xff1a; 以往SD1.5大模型&#xff0c;生成步骤为 Prompt → Base → …

Linux学习第52天:Linux网络驱动实验(三):一往(网)情深

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 许久没有更新&#xff0c;的确是最近有点懈怠了。没有任何借口&#xff0c;接受所有的批评。接下来无论如何也要坚持下去&#xff0c;不管处于什么境地、什么原因&am…

.NET C# 使用GDAL将mdb转换gdb数据

.NET C# 使用GDAL将mdb转换gdb数据 目录 .NET C# 使用GDAL将mdb转换gdb数据1 环境2 Nuget3 Code 1 环境 VisualStudio2022 .NET6 GDAL 3.8.5 2 Nuget 3 Code FeatureExtension.cs public static class FeatureExtension {[DllImport("gdal.dll", EntryPoint &…

前端-echarts tooltip展示多项自定义数据

效果如图&#xff0c;鼠标滑动到某一个柱子的时候&#xff0c;出现这一项数据的多个自定义数据&#xff0c;外加自己的模板样式渲染。 希望能展示每一列中的多个自定义数据 代码部分 主要是在data中&#xff0c;value就是实际展示的主数据&#xff0c;其他字段名为自定义的数…

Matlab进阶绘图第61期—滑珠散点图

滑珠散点图也是一种在《Nature》中常见的数据图。 其功能类似于柱状图&#xff0c;但更加简洁易读。 由于Matlab中没有现成的函数绘制滑珠散点图&#xff0c;因此需要大家自行解决。 本文利用自己制作的BubbleScatter工具&#xff0c;进行滑珠散点图的绘制&#xff0c;先来看…

等保测评初级简答题试题

基本要求&#xff0c;在应用安全层面的访问控制要求中&#xff0c;三级系统较二级系统增加的措施有哪些&#xff1f; 答&#xff1a;三级比二级增加的要求项有&#xff1a; 应提供对重要信息资源设置敏感标记的功能&#xff1b; 应按照安全策略严格控制用户对有敏感标记重要…

贝壳找房基于Flink+Paimon进行全量数据实时分组排序的实践

摘要&#xff1a;本文投稿自贝壳家装数仓团队&#xff0c;在结合家装业务场景下所探索出的一种基于 FlinkPaimon 的排序方案。这种方案可以在实时环境对全量数据进行准确的分组排序&#xff0c;同时减少对内存资源的消耗。在这一方案中&#xff0c;引入了“事件时间分段”的概念…

上涨至13.6分!当之无愧的顶级期刊,影响因子“狂飙”,门槛较低,2个月可录!

本期解析 1、2024年6月20日&#xff0c;科睿唯安正式公布2024年度《期刊引证报告》。 2、本次主要解析Elsevier旗下一本TOP顶刊&#xff0c;期刊表现优秀&#xff0c;在最新的影响因子更新中由12.8上涨至13.6&#xff0c;是一本妥妥评职高分宝刊&#xff01;接下来看看它是否…

Stable Diffusion【真人模型】:人像光影摄影极限写实真实感大模型

大家好&#xff0c;我是极客菌 今天和大家分享一个基于SD1.5的真人大模型&#xff1a;人像光影摄影极限写实真实感大模型。 该模型具有以下特点&#xff1a; 真实肤感&#xff08;在面部肌理和皮肤肌理上均有加强学习&#xff0c;拒绝ai出图假的问题&#xff09; 永不脱妆&a…

经典老动画电影大全,老动画片大全集全部百度网盘,资源下载百度云

当今社会越来越重视学前教育了&#xff0c;今儿童启蒙的教育也越来越受人们的关注和重视。为了满足社会对未来人才的需要&#xff0c;学前教育成为当今教育领域重要角色的一环。当今动画篇是主流&#xff0c;内容精彩纷呈&#xff0c;越来越受到儿童的喜爱。 儿童的语言敏感期&…

ee trade:黄金投资是选择短线交易还是长线投资

黄金投资既可以通过短线交易获取快速收益&#xff0c;也可以采取长线投资策略获得稳健回报。本文将详细比较这两种策略的特点和适用性&#xff0c;为新手投资者提供参考。 短线交易 短线交易指在较短的时间内多次买卖以获取利润&#xff0c;通常交易周期为数日到数周。以下是…

PointCloudLib-KDtree-如何使用 KdTree 进行搜索

在本教程中,我们将介绍如何使用 KdTree 查找特定点或位置的 K 个最近邻,然后我们还将介绍如何查找用户指定的某个半径内的所有邻居(在本例中为随机)。 理论入门 k-d 树或 k 维树是计算机科学中使用的一种数据结构,用于在具有 k 维的空间中组织一定数量的点。它是一个二叉…

用热传感器提高散热片的效率

每天一篇行业发展资讯&#xff0c;让大家更及时了解外面的世界。 更多资讯&#xff0c;请关注B站/公众号【莱歌数字】&#xff0c;有视频教程~~ 散热器的尺寸通常是根据功率、气流、设备热约束和物理几何形状的要求进行冷却应用的。 更大的功耗需要更高性能的散热器或更大、…

记录一个Xshell使用中Xmanager...X11转发的提示问题

希望文章能给到你启发和灵感&#xff5e; 如果觉得有帮助的话&#xff0c;点赞关注收藏支持一下博主哦&#xff5e; 阅读指南 一、环境说明1.1 硬件环境1.2 软件环境 二、问题和错误三、解决四、理解和延伸一下 一、环境说明 考虑环境因素&#xff0c;大家适当的对比自己的软硬…

DBdoctor功能介绍

绍DBdoctor的主要功能&#xff0c;按照事件先后涵盖了事前、事中、事后三个阶段。事前的主动问题发现、SQL性能评估、自动巡检与报表、空间预测与诊断&#xff1b;事中的性能洞察、根因诊断、锁分析、优化建议&#xff1b;事后的审计分析、根因推导、问题快照。按照使用者包含了…

手持小风扇品牌有哪些?分享口碑最好的五款手持小风扇

手持小风扇在炎热的夏季成为了许多人解暑的好帮手。它们不仅轻便便携&#xff0c;随时随地都能为我们带来清凉和舒适。然而&#xff0c;市场上手持小风扇的品牌繁多&#xff0c;让人眼花缭乱。为了帮助大家做出更明智的选择&#xff0c;接下来我们将分享口碑最好的五款手持小风…

RAG | (ACL24规划-检索增强)PlanRAG:一种用于生成大型语言模型作为决策者的规划检索增强生成方法

原文&#xff1a;PlanRAG: A Plan-then-Retrieval Augmented Generation for Generative Large Language Models as Decision Makers 地址&#xff1a;https://arxiv.org/abs/2406.12430 代码&#xff1a;https://github.com/myeon9h/PlanRAG 出版&#xff1a;ACL 24 机构: 韩国…

MQTT自动回复消息工具

点击下载《MQTT自动回复消息工具V1.0.0》 1. 前言 在进行IoT系统开发时&#xff0c;各个小组成员通常是同步进行项目开发&#xff0c;经常会遇到设备端和前后端开发人员开发进度不协调的情况&#xff0c;此时接口还没开发完&#xff0c;也没有可以调试的环境&#xff0c;只能…