写点什么

一种清晰, 便于扩展 android 项目架构方案,kotlin 编程

用户头像
Android架构
关注
发布于: 刚刚
  • personal

  • data

  • ui

  • xxxViewModelFactory

  • xxxViewModel此处可能需要获取用户信息,则直接调用core/data里的UserRepository


以下对上面的结构进行说明

core 目录

服务于整个工程,一些基础代码。关于系统配置,用户信息等数据的操作全部放在这个里面。


  • data目录:DAO 相关的操作,model包下面的是 pojo, 数据的获取或持久化全部由xxxRepository去调用datasource包下面的数据源去实现

  • util目录:放置一些公共的工具类

  • view目录: 放置公共的自定义 view,这些自定义 view 脱离具体的业务联系,能够在各业务模块使用

  • base目录:用来放置一些基础的组件,如BaseActivity, BaseFragment, BaseViewModel

features 目录

按业务模块来划分不同的包,组织在该目录下。以下对代码的组织做一些说明

login 模块

在上面的目录中,由于涉及到用户登录相关的 DAO 操作都已经放到core目录下了, 假设可以满足要求,那么login模块下只有 UI 相关文件和ViewModel,xxxViewModelFactory

product 模块

这个模块是用来模拟某个模块下多个页面的场景。以商品列表页和详情页为例。由于 DAO 的操作可能会有重叠的场景,这里将它们的数据操作写在一起。UI 层面按功能再分为list, detail两个包。list, detail两个页面的 ViewModel 可以采用同一个 ViewModelFactory 来创建。


  • rendermodel包:这个目录下有一个需要单独说明一下,当我们从服务器拿到数据了如ProductInfo之后,将数据显示在页面上,我们显示在页面上的一些信息很有可能是需要根据ProductInfo的数据进行加工的。为此,我们定义一个ProductInfoRenderModel.java用来承载只需要显示在页面上的数据。ProductInfoRenderModel.java则放在rendermodel包下面。

personal 模块

personal模块中也会涉及到用户相关的信息,这也就是为什么一开始设计把用户相关信息的 dao 操作放到core目录下。personal模块下的xxViewModel如果要查用户相关的信息,可以直接调用core下面的UserRepository


至此,整个项目的大体架构便梳理完成了。采用这种方案将代码以功能模块进行划分,方便后期的维护。既使后续某个模块中进行了技术方案的改革,也能保证其影响的粒度最小。当然这里面主要是为了说明项目的主要结构,在实际项目中,除了这些,我们还会有adapter, 自己写的各种工具等等,这个就根据实际情况再自己分包了。接下来我们看一下涉及到的相关技术栈

技术栈

在这种项目架构中我们主要用到的技术栈有Jetpack中的ViewModel, ViewModelFactory, LiveData, ROOM,下面简单介绍一下这几种技术以及它们之间的整合。当然用于网络请求相关的我们可以用Okhttp, retrofit,此处就不介绍。

ViewModel

Jetpack组件中提供了ViewModel可以方便的将数据,对象与组件的生命周期绑定起来,方便进行组件间的数据共享,如一个activity中多fragment的情况。同时它可以有效的从架构层面上进行解藕,和 mvp 架构模式相比,可以大大减少接口/方法的个数。以登录为例,用户调用登录接口时需要调用 presenter.login 方法,login 成功后调用 view.loginSuccess方法。而采用ViewMode后,用户在登录时调用viewModel.login方法,登录成功后,更新ViewModel中的LiveData,然后在调用处观察LiveData做相应的行为就可以。

ViewModelProvider.Factory

用来创建ViewModel,ViewModel不可以自己创建,必须要借助ViewModelProvider.Factory来创建。在创建时通常为 ViewModel 指定数据仓库,如下:


public class LoginViewModelFactory implements ViewModelProvider.Factory {@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {if (modelClass.isAssignableFrom(LoginViewModel.class)) {return (T) new LoginViewModel(LoginRepository.getInstance(new LoginDataSource()));} else {throw new IllegalArgumentException("Unknown ViewModel class");}}}

LiveData

在数据发生变化时,需要通知给页面。通常可以采用接口的方工去做,但如果要观察的数据很多,就需要定义大量的接口,代码会十分冗余。为此, Google 提供了LiveData组件,它是一个可被观察的数据容器类,将数据包装起来,使数据成为被观察者,当该数据发生变化时,观察者能获得通知。


ViewModel是用来存储数据,LiveData的作用是在ViewModel发生变化时通知页面。因此, LiveData通常放在ViewModel中使用,用于包装ViewModel中那些需要被外界观察的数据。


我们来结合具体的例子(登录)看这三者的配合使用

示例

UI 层面(LoginActivity)

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityLoginBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());...viewModel = new ViewModelProvider(this, new LoginViewModelFactory()).get(LoginViewModel.class);registerObserver();bindClickEvent();


}


private void registerObserver() {viewModel.getLoginResult().observe(this, new Observer<LoginResult>() {@Overridepublic void onChanged(LoginResult loginResult) {if (loginResult.success) {//登录成功}}});//出现异常 viewModel.exceptionLiveData.observe(this, new Observer<AppException>() {@Overridep


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


ublic void onChanged(AppException e) {Toast.makeText(LoginActivity.this, e.getBizMsg(), Toast.LENGTH_SHORT).show();}});


}


private void bindClickEvent() {binding.btnLogin.setOnClickListener(v-> {viewModel.login(phone, pwd, verifyCode, verifyKey);});}


  • 采用ViewBinding进行资源的绑定

  • 绑定ViewModel

  • ViewModel监听数据的变化

  • 利用ViewModel去访问数据

ViewModel

public class LoginViewModel extends BaseViewModel {...private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>();


private LoginRepository loginRepository;


LoginViewModel(LoginRepository loginRepository) {this.loginRepository = loginRepository;}


public LiveData<LoginResult> getLoginResult() {return loginResult;}


public void login(String username, String password, String verifyCode, String verifyKey) {loginRepository.login(username, password, verifyCode, verifyKey, new Gson2ModelCallback<NetResult<LoginNetResponse>>() {


@Overridepublic void onSuccess(NetResult<LoginNetResponse> result) {//成功 if ("SUCCESS".equals(result.getCode())) {


loginResult.postValue(new LoginResult(result.getData()));}}


@Overridepublic void onFail(Throwable e) {handleException(e);}});}}其功能是调用 repository 相关的业务方法去拿数据,拿到数据后通过postValue方法再传递给ViewModel

Repository

Repository层便会调用具体的数据源去加载数据,这里就不详情说明。Repository在创建ViewModel的时候就已经注入了。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
一种清晰, 便于扩展android项目架构方案,kotlin编程