当前位置: 首页 > news >正文

Android 开发架构

文章目录

    • MVC
    • MVP
    • MVVM
    • 总结
    • Clean Archtechure(MVVM + Clean Architecture)
      • Domain 层(核心逻辑,不依赖 Android)
        • 1)Entity:业务对象
        • 2)Repository 接口(抽象数据访问)
        • 3)UseCase(业务动作)
      • Data 层(具体实现 Repository)
      • Presentation 层(UI)
        • ViewModel
        • UI

MVC

  • M:Model,数据模块,提供数据。(它不仅是一个 entity,也是包含获取数据的)
  • V:View,UI 模块,视图层。
  • C:Controller,控制模块,相当于 Activity。

它的特点是,Activity 同时控制 View 和 Model,所有的逻辑都在 Activity 中,太臃肿,不利于测试与维护。仅仅适合简单的 Demo。

// Model:数据类
public class User {private String name;public User(String name) { this.name = name; }public String getName() { return name; }public void setName(String name) { this.name = name; }
}// View + Controller:Activity同时控制UI与逻辑
public class MainActivity extends AppCompatActivity {private EditText etName;private TextView tvResult;private Button btnSave;private User user; // Model@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etName = findViewById(R.id.etName);tvResult = findViewById(R.id.tvResult);btnSave = findViewById(R.id.btnSave);user = new User("Default");btnSave.setOnClickListener(v -> {// Controller逻辑直接写在ActivityString newName = etName.getText().toString();user.setName(newName);tvResult.setText("Hello, " + user.getName());});}
}

MVP

  • P:Presenter,演示层,连接 View 和 Model,处理业务逻辑,更新 View。

这一层主要出现的目的就是,让 Activity 中只提供对 UI 的操作方式;让 Model 提供对数据的操作的逻辑;Presenter 调用上面两者,实现具体的业务逻辑。(最终调用 Presenter 的地方还是在 Activity 中,要喂给它 ViewImpl,但逻辑是在 Presenter 中做的)

这么做的好处就是不用在 Activity 里实现逻辑了,而是放在 Presenter 中,解耦。而且 Presenter 可以进行单元测试。(单元测试要求:在普通 JVM 环境运行、不依赖 Android Framework。但 Activity,需要系统 Context、有 UI 生命周期、依赖 View 树等,没法写单元测试)

// 定义契约接口(约定View与Presenter的职责)
interface UserContract {interface View {void showUserName(String name);}interface Presenter {void onSaveButtonClicked(String input);}
}
// Model
class UserModel {private String name = "Default";public void setName(String name) { this.name = name; }public String getName() { return name; }
}
// Presenter(中间层)
class UserPresenter implements UserContract.Presenter {private final UserContract.View view;private final UserModel model;public UserPresenter(UserContract.View view) {this.view = view;this.model = new UserModel();}@Overridepublic void onSaveButtonClicked(String input) {model.setName(input);view.showUserName("Hello, " + model.getName());}
}
// Activity只负责展示,不写逻辑
public class MainActivity extends AppCompatActivity implements UserContract.View {private EditText etName;private TextView tvResult;private Button btnSave;private UserPresenter presenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etName = findViewById(R.id.etName);tvResult = findViewById(R.id.tvResult);btnSave = findViewById(R.id.btnSave);presenter = new UserPresenter(this);btnSave.setOnClickListener(v ->presenter.onSaveButtonClicked(etName.getText().toString()));}@Overridepublic void showUserName(String name) {tvResult.setText(name);}
}

MVVM

  • VM:ViewModel,连接 View 与 Model,通过 LiveData(还可以别的方式)让数据自动驱动 UI 更新

可以看到,上面 MVP 会有大量的 View 接口,Presenter 会大量回调 View 接口。

比起 MVP,MVVM 利用 LiveData 中 observe() 的特性,不再需要 View 接口,不在需要手动回调,把对 UI 的操作又放回了 Activity 中,Activity 中可以自动观察数据变化,然后执行相应 UI 操作,减少了回调接口的这种方式。

// Model
public class User {public MutableLiveData<String> name = new MutableLiveData<>("Default");
}
// ViewModel
public class UserViewModel extends ViewModel {private final User user = new User();public LiveData<String> getName() { return user.name; }public void updateName(String newName) {user.name.setValue(newName);}
}
// Activity(观察 LiveData)
public class MainActivity extends AppCompatActivity {private EditText etName;private TextView tvResult;private Button btnSave;private UserViewModel viewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);etName = findViewById(R.id.etName);tvResult = findViewById(R.id.tvResult);btnSave = findViewById(R.id.btnSave);viewModel = new ViewModelProvider(this).get(UserViewModel.class);// View 自动响应数据变化viewModel.getName().observe(this, name -> {tvResult.setText("Hello, " + name);});btnSave.setOnClickListener(v ->viewModel.updateName(etName.getText().toString()));}
}

总结

  • MVC:对 View、Model 的操作都放在了Activity 中(Controller + View),逻辑严重耦合。
  • MVP:Activity 只负责 UI,提供 ViewImpl(View 相应的操作) 给 Presenter,在 Presenter 中完成对 View 和 Model 的操作逻辑。也就是比如 Activity 触发一个点击事件,Activity 直接调用 Presenter 的接口,剩下都不用管了。
  • MVVM:为避免太多 View 接口及其回调,利用 LiveData 动态监听的方式,对 UI 的操作又回到了 Activity 中。当 ViewModel 中相应的值发生变化,Activity 会监听到,然后做相应的 UI 更新。比起 MVP,也就是 Presenter 不用在处理回调了,只需处理相应的业务逻辑。

Clean Archtechure(MVVM + Clean Architecture)

以上是最传统的 Android 架构方式,在我们公司中又引入了 Clean Archtechure 的概念。对于 Android,看向右下这条线就可以了,这里的 Presenter 是 MVP 中的写法,而我下面的例子是基于 MVVM 的。
在这里插入图片描述

Clean Architecture 最根本的规则是:源代码依赖关系必须只指向内层,而不能指向外层。内层代码不应该知道任何关于外层代码的事情。

在 Android 开发中,Clean Architecture 通常被具体化为三个主要层次:

  • Domain Layer(领域层)
    • Entity:业务对象,不依赖 Android。
    • Repository 接口:只定义数据获取规则,不关心数据来源。
    • UseCase:封装业务动作,UI 只调用 UseCase。
  • Data Layer(数据层)
    • 实现 Repository 接口,访问实际数据源。可以随时替换数据来源,而 Domain 或者 Presentation 不需要任何修改。
  • Presentation Layer(表现层)
    • ViewModel,调用 UseCase,不直接访问底层数据源。
    • Fragment / Activity,根据 ViewModel 的回调,进行 UI 变更。

下面介绍一个例子,目录结构:

clean_arch_example
│
├── domain
│   ├── entity
│   │   └── LoginResult.java
│   ├── repository
│   │   └── UserRepository.java
│   └── usecase
│       └── LoginUseCase.java
│
├── data
│   └── UserRepositoryImpl.java
│
└── presentation├── LoginViewModel.java└── LoginFragment.java

Domain 层(核心逻辑,不依赖 Android)

1)Entity:业务对象
public class LoginResult {private final boolean success;private final String message;public LoginResult(boolean success, String message) {this.success = success;this.message = message;}public boolean isSuccess() { return success; }public String getMessage() { return message; }
}
2)Repository 接口(抽象数据访问)

在 Domain 层里只定义规则,不关心数据从哪里来。

public interface UserRepository {LoginResult login(String username, String password);
}
3)UseCase(业务动作)

UseCase 是业务逻辑聚合点,Presentation 永远只和 UseCase 交互。

比如执行登录逻辑

public class LoginUseCase {private final UserRepository repository;public LoginUseCase(UserRepository repository) {this.repository = repository;}public LoginResult execute(String username, String password) {if (username.isEmpty() || password.isEmpty()) {return new LoginResult(false, "用户名或密码不能为空");}return repository.login(username, password);}
}

Data 层(具体实现 Repository)

Data 层可以换成,Retrofit 网络请求、数据库、文件等,但 Domain 与 Presentation 层都不需要改。而且也更方便 Mock 测试。

这里模拟登录数据来自“后台服务器”。

public class UserRepositoryImpl implements UserRepository {@Overridepublic LoginResult login(String username, String password) {// 模拟网络请求if ("admin".equals(username) && "123456".equals(password)) {return new LoginResult(true, "登录成功!");}return new LoginResult(false, "用户名或密码错误");}
}

Presentation 层(UI)

ViewModel

P 层使用 ViewModel 的方式,这也是为什么我在标题后面加了“(MVVM + Clean Architecture)”。当然也可以使用 MVP 中 Presenter 呢种方式。

public class LoginViewModel extends ViewModel {private final MutableLiveData<LoginResult> loginResultLiveData = new MutableLiveData<>();private final LoginUseCase loginUseCase;public LoginViewModel() {// Data层UserRepository repository = new UserRepositoryImpl();// Domain层UseCasethis.loginUseCase = new LoginUseCase(repository);}public LiveData<LoginResult> getLoginResult() {return loginResultLiveData;}public void onLoginButtonClicked(String username, String password) {LoginResult result = loginUseCase.execute(username, password);loginResultLiveData.postValue(result);}
}
UI
public class LoginFragment extends Fragment {private EditText editUsername;private EditText editPassword;private Button btnLogin;private TextView tvResult;private LoginViewModel viewModel;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_login, container, false);editUsername = view.findViewById(R.id.edit_username);editPassword = view.findViewById(R.id.edit_password);btnLogin = view.findViewById(R.id.btn_login);tvResult = view.findViewById(R.id.tv_result);setupViewModel();setupObserver();setupListener();return view;}private void setupViewModel() {viewModel = new ViewModelProvider(this).get(LoginViewModel.class);}private void setupObserver() {viewModel.getLoginResult().observe(getViewLifecycleOwner(), result -> {if (result != null) {tvResult.setText(result.getMessage());}});}private void setupListener() {btnLogin.setOnClickListener(v -> {String username = editUsername.getText().toString().trim();String password = editPassword.getText().toString().trim();viewModel.login(username, password);});}
}
http://www.dtcms.com/a/619232.html

相关文章:

  • 深入理解Ansible条件语句:从基础到高级应用
  • 怎样做海外淘宝网站地方生活门户网站有哪些
  • 学习周报二十二
  • 软件第三方检测机构选择的五大关键问题
  • 整站网站优化运营加强学院网站建设
  • 网站开发项目报告书商标设计网软件
  • 【电工】网线(T568B线序)的制作
  • 香蕉叶子病害分类数据集898张4类别
  • 用AI点亮心扉:我的数字人才技能大赛参赛项目——“心语之光”智能体全解析
  • 制作企业官网重庆seo案例
  • 【Linux驱动开发】Linux块设备驱动开发详解
  • 做私人网站 违法深圳seo优化多少钱
  • 做毕业设计免费网站建设vs和dw做网站的区别
  • 怎么把网站源码扒下来昆明网签备案查询系统
  • PPTX 中加入输入框和按钮,文本框不为空点击按钮跳转
  • Spring ResponseEntity 全面详解
  • 如何统计网站访问量wordpress能仿站吗
  • 注册网站后邮箱收到邮件酒店类网站开发策略
  • 北京昌盛宏业网站建设wordpress站点管理
  • intitle 网站建设大余网站
  • 单元级别性能测试
  • FPGA外部存储器深度解析 (二)深入理解DDR3基础与FPGA控制器
  • 做网站考什么赚钱wordpress 伪静态配置
  • 建各企业网站多少钱新安人才网
  • 最先进的深圳网站建设徐州招标网
  • Bootstrap4 Jumbotron详解
  • 手机网站默认全屏服装行业网站建设
  • 珠海网站备案网络服务商的责任规范
  • wordpress建站简单吗网站制作需要多少钱品牌
  • 成都网站建设哪里有网站空间的分类