(三十)安卓开发中的MVP模式详解

news2025/4/22 14:30:33

在安卓开发中,MVP(Model-View-Presenter) 是一种常见的软件架构模式,它通过将应用程序的逻辑与用户界面分离,使得代码更加模块化、易于维护和测试。本文将详细讲解MVP模式的组成部分、工作流程、优点,并结合代码示例和具体的使用场景,帮助你深入理解其在安卓开发中的应用。


1. MVP模式的组成部分

MVP模式由以下三个核心部分组成:

  • Model(模型)
    负责处理应用程序的数据和业务逻辑。Model与数据源(如数据库、网络请求)交互,获取或更新数据。它不关心数据如何展示,只专注于数据本身。

  • View(视图)
    负责显示用户界面,并将用户的操作(如点击按钮)传递给Presenter。在安卓中,View通常是Activity、Fragment或自定义View。

  • Presenter(呈现者)
    充当View和Model之间的桥梁。它从Model获取数据并传递给View进行显示,同时处理View中的用户操作并更新Model。


2. MVP模式的工作流程

MVP模式的工作流程可以分为以下几个步骤:

  1. 用户与View交互
    用户在View上执行操作,例如点击登录按钮。

  2. View通知Presenter
    View将用户的操作传递给Presenter,而不是直接处理逻辑。

  3. Presenter处理逻辑
    Presenter根据用户操作,决定是否需要从Model获取数据或更新Model。

  4. Model处理数据
    如果需要,Presenter调用Model的方法来获取或更新数据(可能是网络请求或数据库操作)。

  5. Presenter更新View
    Model返回数据后,Presenter将数据传递给View,View再更新用户界面。

这种流程确保了View和Model之间的解耦,所有的逻辑处理都集中在Presenter中。


3. MVP模式的优点

  • 解耦
    View和Model之间没有直接依赖,通过Presenter通信,使得代码结构更清晰。

  • 易于测试
    Presenter不依赖安卓框架,可以通过单元测试轻松验证业务逻辑。

  • 可重用性
    Presenter可以被多个View重用,提高代码的复用性。


4. 代码示例:实现简单的登录功能

下面通过一个登录功能的示例,展示MVP模式的具体实现。

4.1 Model(模型)

public class LoginModel {
    public void login(String username, String password, Callback callback) {
        // 模拟网络请求,延迟2秒返回结果
        new Handler().postDelayed(() -> {
            if ("admin".equals(username) && "password".equals(password)) {
                callback.onSuccess();
            } else {
                callback.onFailure();
            }
        }, 2000);
    }

    // 回调接口,用于异步返回结果
    public interface Callback {
        void onSuccess();
        void onFailure();
    }
}

说明LoginModel 模拟了一个登录的网络请求,检查用户名和密码是否正确,并通过回调返回结果。

4.2 View(视图接口)

public interface LoginView {
    void showLoading();  // 显示加载动画
    void hideLoading();  // 隐藏加载动画
    void showSuccess();  // 显示登录成功
    void showFailure();  // 显示登录失败
}

说明LoginView 是一个接口,定义了视图需要实现的方法,Presenter通过这些方法更新UI。

4.3 Presenter(呈现者)

public class LoginPresenter {
    private LoginView view;
    private LoginModel model;

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

    public void login(String username, String password) {
        view.showLoading();  // 显示加载状态
        model.login(username, password, new LoginModel.Callback() {
            @Override
            public void onSuccess() {
                view.hideLoading();
                view.showSuccess();
            }

            @Override
            public void onFailure() {
                view.hideLoading();
                view.showFailure();
            }
        });
    }
}

说明LoginPresenter 持有 LoginViewLoginModel 的引用,负责协调两者的交互。它在登录时显示加载状态,并在结果返回后更新UI。

4.4 Activity(实现View接口)

public class LoginActivity extends AppCompatActivity implements LoginView {
    private EditText etUsername;
    private EditText etPassword;
    private Button btnLogin;
    private ProgressBar progressBar;
    private LoginPresenter presenter;

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

        etUsername = findViewById(R.id.et_username);
        etPassword = findViewById(R.id.et_password);
        btnLogin = findViewById(R.id.btn_login);
        progressBar = findViewById(R.id.progress_bar);

        presenter = new LoginPresenter(this);

        btnLogin.setOnClickListener(v -> {
            String username = etUsername.getText().toString();
            String password = etPassword.getText().toString();
            presenter.login(username, password);
        });
    }

    @Override
    public void showLoading() {
        progressBar.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void showSuccess() {
        Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showFailure() {
        Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show();
    }
}

布局文件(R.layout.activity_login)示例

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/et_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="用户名" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密码"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录" />

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone" />
</LinearLayout>

说明LoginActivity 实现了 LoginView 接口,负责UI的显示和用户交互。当用户点击登录按钮时,它将输入传递给Presenter处理。


5. 具体使用场景

MVP模式适用于多种安卓开发场景,以下是一些典型例子:

  • 登录功能
    如上例所示,MVP将登录的UI(如输入框、按钮)和业务逻辑(验证用户名和密码)分离。

  • 列表展示
    Presenter从Model获取数据(如商品列表),然后传递给View(如RecyclerView)进行展示。

  • 表单提交
    View收集用户输入(如注册表单),Presenter验证输入的合法性并提交到Model保存。

  • 复杂业务逻辑
    当业务逻辑复杂时,MVP将逻辑集中在Presenter中,避免Activity或Fragment变得臃肿。


6. 注意事项

  • 内存泄漏
    Presenter持有View的引用时,需要在Activity或Fragment销毁时释放引用(例如在 onDestroy 中置为null),以避免内存泄漏。

  • 接口设计
    View和Presenter之间的接口应保持简洁,避免定义过多方法,否则会增加维护成本。

  • 异步操作
    处理异步任务(如网络请求)时,需确保UI更新在主线程执行,通常使用Handler或线程切换工具。


7. 总结

MVP模式通过将用户界面(View)、数据处理(Model)和逻辑控制(Presenter)分离,显著提高了安卓应用程序的可维护性、可测试性和模块化程度。通过上述代码示例和使用场景,你可以看到MVP如何在实际开发中发挥作用。无论是简单的登录功能还是复杂的业务逻辑,MVP都是一种值得掌握的架构模式。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于MuJoCo物理引擎的机器人学习仿真框架robosuite

Robosuite 基于 MuJoCo 物理引擎&#xff0c;能支持多种机器人模型&#xff0c;提供丰富多样的任务场景&#xff0c;像基础的抓取、推物&#xff0c;精细的开门、拧瓶盖等操作。它可灵活配置多种传感器&#xff0c;提供本体、视觉、力 / 触觉等感知数据。因其对强化学习友好&am…

13.编码器的结构

从入门AI到手写Transformer-13.编码器的结构 13.编码器的结构代码 整理自视频 老袁不说话 。 13.编码器的结构 T r a n s f o r m e r E n c o d e r : 输入 [ b , n ] TransformerEncoder:输入[b,n] TransformerEncoder:输入[b,n] E m b e d d i n g : − > [ b , n , d ]…

[原理分析]安卓15系统大升级:Doze打盹模式提速50%,续航大幅增强,省电提升率5%

技术原理:借鉴中国友商思路缩短进入Doze的时序 开发者米沙尔・拉赫曼(Mishaal Rahman)在其博文中透露&#xff0c;谷歌对安卓15系统进行了显著优化&#xff0c;使得设备进入“打盹模式”(Doze Mode)的速度提升了50%&#xff0c;并且部分机型的待机时间因此得以延长三小时。设备…

cdp-(Chrome DevTools Protocol) browserscan检测原理逆向分析

https://www.browserscan.net/zh/bot-detection 首先,打开devtools后访问网址,检测结果网页显示红色Robot,标签插入位置,确定断点位置可以hook该方法,也可以使用插件等方式找到这个位置,本篇不讨论. Robot标签是通过insertBefore插入的. 再往上追栈可以发现一个32长度数组,里面…

【Java面试笔记:基础】1.谈谈你对Java平台的理解?

前言 Java 是历史悠久且主流的编程语言&#xff0c;拥有庞大的开发者群体和广泛的应用领域。通过系统学习和实践&#xff0c;构建扎实的 Java 知识体系&#xff0c;提升面试成功率 笔记核心内容 1. Java 平台的核心特性 跨平台特性&#xff1a;Java 的核心特性之一是“Writ…

Java第五节:继承thread类创建线程

1、创建类Thread01 创建类Thread01然后继承thread类 2、重写run函数 3、运行线程 在主函数创建两个线程&#xff0c;并执行。

C#/.NET/.NET Core技术前沿周刊 | 第 35 期(2025年4.14-4.20)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

《MySQL:MySQL表的基本查询操作CRUD》

CRUD&#xff1a;Create&#xff08;创建&#xff09;、Retrieve&#xff08;读取&#xff09;、Update&#xff08;更新&#xff09;、Delete&#xff08;删除&#xff09;。 Create into 可以省略。 插入否则更新 由于主键或唯一键冲突而导致插入失败。 可以选择性的进行同步…

多维度信息捕捉:利用向量、稀疏向量、全文搜索及张量实现RAG的极致性能

开源 AI 原生数据库 Infinity 0.2 release 正式发布&#xff0c;提供了 2 种新数据类型&#xff1a;稀疏向量Sparse Vector 和 张量Tensor&#xff0c;在此前的全文搜索和向量搜索之外&#xff0c; Infinity 提供了更多的召回手段&#xff0c;如下图所示&#xff0c;用户可以采…

vscode使用remote ssh插件连接服务器的问题

本人今天发现自己的vscode使用remote ssh连接不上服务器了&#xff0c;表现是&#xff1a;始终在初始化 解决方法&#xff1a; 参考链接&#xff1a;vscode remote-ssh 连接失败的基本原理和优雅的解决方案 原因 vscode 的 SSH 之所以能够拥有比传统 SSH 更加强大的功能&a…

神经网络优化 - 小批量梯度下降之批量大小的选择

上一博文学习了小批量梯度下降在神经网络优化中的应用&#xff1a; 神经网络优化 - 小批量梯度下降-CSDN博客 在小批量梯度下降法中&#xff0c;批量大小(Batch Size)对网络优化的影响也非常大&#xff0c;本文我们来学习如何选择小批量梯度下降的批量大小。 一、批量大小的…

Novartis诺华制药社招入职综合能力测评真题SHL题库考什么?

一、综合能力测试 诺华制药的入职测评中&#xff0c;综合能力测试是重要的一部分&#xff0c;主要考察应聘者的问题解决能力、数值计算能力和逻辑推理能力。测试总时长为46分钟&#xff0c;实际作答时间为36分钟&#xff0c;共24题。题型丰富多样&#xff0c;包括图形变换题、分…

C语言学习记录(16)文件操作7

前面学的东西感觉都跟写代码有关系&#xff0c;怎么突然就开始说文件了&#xff0c;有什么用呢&#xff1f; 其实&#xff0c;文件是另一种数据存储的方式&#xff0c;学会使用文件就可以让我们的数据持久的保存。 一、文件是什么 就算没有学过相关的知识&#xff0c;在这么…

《作用域大冒险:从闭包到内存泄漏的终极探索》

“爱自有天意&#xff0c;天有道自不会让有情人分离” 大家好&#xff0c;关于闭包问题其实实际上是js作用域的问题&#xff0c;那么js有几种作用域呢&#xff1f; 作用域类型关键字/场景作用域范围示例全局作用域var&#xff08;无声明&#xff09;整个程序var x 10;函数作用…

让数据应用更简单:Streamlit与Gradio的比较与联系

在数据科学与机器学习的快速发展中&#xff0c;如何快速构建可视化应用成为了许多工程师和数据科学家的一个重要需求。Streamlit和Gradio是两款备受欢迎的开源库&#xff0c;它们各自提供了便捷的方式来构建基于Web的应用。虽然二者在功能上有许多相似之处&#xff0c;但它们的…

LlamaIndex 生成的本地索引文件和文件夹详解

LlamaIndex 生成的本地索引文件和文件夹详解 LlamaIndex 在生成本地索引时会创建一个 storage 文件夹&#xff0c;并在其中生成多个 JSON 文件。以下是每个文件的详细解释&#xff1a; 1. storage 文件夹结构 1.1 docstore.json 功能&#xff1a;存储文档内容及其相关信息。…

AndroidRom定制删除Settings某些菜单选项

AndroidRom定制删除Settings某些菜单选项 1.前言. 最近在Rom开发中需要隐藏设置中的某些菜单&#xff0c;launcher3中的定制开发&#xff0c;这个属于很基本的定制需求&#xff0c;和隐藏google搜素栏一样简单&#xff0c;这里我就不展开了&#xff0c;直接上代码. 2.隐藏网络…

【数据结构和算法】3. 排序算法

本文根据 数据结构和算法入门 视频记录 文章目录 1. 排序算法2. 插入排序 Insertion Sort2.1 概念2.2 具体步骤2.3 Java 实现2.4 复杂度分析 3. 快排 QuickSort3.1 概念3.2 具体步骤3.3 Java实现3.4 复杂度分析 4. 归并排序 MergeSort4.1 概念4.2 递归具体步骤4.3 Java实现4.4…

FreeRTos学习记录--2.内存管理

后续的章节涉及这些内核对象&#xff1a;task、queue、semaphores和event group等。为了让FreeRTOS更容易使用&#xff0c;这些内核对象一般都是动态分配&#xff1a;用到时分配&#xff0c;不使用时释放。使用内存的动态管理功能&#xff0c;简化了程序设计&#xff1a;不再需…

HAL库(STM32CubeMX)——高级ADC学习、HRTIM(STM32G474RBT6)

系列文章目录 文章目录 系列文章目录前言存在的问题HRTIMcubemx配置前言 对cubemx的ADC的设置进行补充 ADCs_Common_Settings Mode:ADC 模式 Independent mod 独立 ADC 模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选 ADC_Se…