最近在做一功能不大、业务也不复杂的小众App,以往做App是发现自己从来没有考虑过一些架构方面的问题,只是按照自己以往的习惯去写代码,忽略了App的设计。本次分享主要包含一些开发App的小经验和技巧,来一次App开发与设计的分享。

先和分享下一下**实体类的设计与组织形式**

### 实体类的组织

在做App开发的时候有很多的实体类,项目越复杂实体类就会越多,经过我的一番思考大致这可以将实体分为以下几大数:

* 面向数据库的
* 服务端返回的数据实体
* 用于渲染View的实体(使用Databinding)

一般情况下实体类的操作会经过以下步骤:

1. App请求服务器获取数据
2. 将数据存入数据库(可选)
3. 渲染页面展示数据

![21](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944223-1662304384.png)

现在的实体的产生只用在请求服务器数据的时候才需要新建,后续的数据库、页面渲染其实是可以使用一套实体:

![22](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944408-1718550849.png)

先不说这样做的行不行,首先三个地方使用同一实体就会引起字段歧义比如服务器数据有Id、本地数据也有Id,那两个id字段就有冲突了不得不改字段名。

另一种情况渲染和数据本身并不会一一对应,有时候后端数据给的是一个纯数字而前端页面显示的是字符串两个都对应不上,强行放在一起会起来更多的问题。

所为实体类的的正确组织形式应该是:**相互隔离、互不干扰**:

![23](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944546-1321776412.png)

数据实体的在渲染之前都需要准备好,比如在ViewModel中将int型的数据转换成文本型的数据然后再使用Databinding+页面渲染实体来渲染页面。

### 优雅的处理网络数据

现在Android开发使用的网络库大部分都是`Okhttp + Retrofit`,使用Retrofit网络交互变的非常简单一个Service接口就能搞定一切,美兹兹~~,现在大部分后端返回的数据都会是以下形式:

```json
{
"code":0,
"data": {},
"msg": ""
}
```

虽然不能涵盖所有,但还是可以非常赞的数据、消息、成功与否啥都有!对于前面主要是关注`data`字段,其他`msg`、`code`等都属于辅助字段。前端对应的实体对象应该是这样的(假代码):

```java
public class ApiResponse {
private int code;
private T data;
private String msg;
}
```

对应的Service那就得定义成这样(使用了RxJava):

```java
public intface UserService {
@GET("/xx/{id}")
Single getUserInfoById(@Path("id") Long userId);
}
```

从接口中可以看出来,方法的返回值就包了几层,如果要拿`data`字段需要经过:`ApiResponse -> UserInfo`,而且在拿之前还要判断`code`字段:

```java

...

if(ApiResponse.code == 0){
UserInfo info = ApiResponse.getData();
}

...

```

为了消除这些冗余的代码可以使用`CallAdapter`来使Service方法返回的数据直接就是实体类:

```java
public intface UserService {
@GET("/xx/{id}")
Single getUserInfoById(@Path("id") Long userId);
}
```

`CallAdapter`的代码就不贴了,可以自行查找。这样做带来的另外一个问题就是**业务代码如何判断接口是否成功或失败**,前端必需友好的把错误提示给用户而不是一直搞个Loading在那里瞎转~~。现阶段最方便的的错误传递方式是使用**Java异常**,前端可以定义**业务异常**或**网络异常**:

```java
public class BizException extends RuntimeException {
...
}
```

在`CallAdapter`中检查ApiResponse的返回值是否成功:

```

if(!ApiResponse != 0){
throw new BizExcepiton(ApiResponse);
}

```

如果后端返回业务异常那前端就对应抛出一个`BizExcepiton`,如果是http错误如:404、400那可以抛出`HttpException`。除了`BizExcepiton`和`HttpException`外还可使用特定的异常比如后端返回密码错误异常:

```
public class InvalidPasswordException extends BizException {
...
}
```

如需特殊处理,也可以满足要求。

### 健壮的数据层

现在很多应用都开发使用MVVM开发模式数据层都使用`Repository`来表示,面向**数据驱动**的开发模式,页面变化都需要随着数据变更而更新,**数据发生变化然后页面再做出响应**。Repository的拆分要细一点,不建议简单的弄个`UserRepository`包含登陆、注册、更新密码等等操作,设计`Repository`的一些想法:

1. 面向接口编程
2. 保持**单一原则**
3. 功能边界要清晰(如:登陆、注册可以分开)
4. 业务逻辑尽可能的少(复杂的业务考虑Presenter)

一个判断是否是好的设计的办法可以这样:一个登陆页面从Activive/Fragment到ViewModel再到Repository,有没有多余的代码。比如上面说的`UserRepository`包含登陆、注册但是在一个登陆页面就不需要有注册功能,从登陆页面上来看注册的代码就是多余的(有些App登陆/注册在一个页面的~~)。

一个包含登陆、注册的`UserRepository`简单图:

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153944720-1390455330.png)

另外一点是尽量将repository使用到的一些东西集中管理,可引入一个基础的repository:

```java
public class SimpleRepository {

protected final T getService(Class clz){
return Services.getService(clz);
}
}

```

做为`SimpleRepository`的子类,就不需要考虑从哪里获取service的问题。

### 简洁的UI层

UI层面可以分为ViewModel和View(Activity/Fragment), View的职责应当只有二点:

1. 展示业务数据
2. 收集业务数据

例如一些数据的组织、判断都不应该出现在View中比如:
```java
if (Strings.isNullOrEmpty(phone)) {
...
return;
}

if (Strings.isNullOrEmpty(pwd)) {
...
return;
}
```

像上面这类的代码都不应该出现在View中,而在放置在ViewModel里面,View只**收集用户数据**传递给ViewModel由它来进行数据校验。再比如像这样的if/else代码也应该放置在ViewModel中:

```
int age = 10;
String desc = "";
if(age (this));
```

一旦数据发生变化`LiveData`就会通知Observer更新,通过DataBinding更新各个页面数据。

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153945197-2132211433.png)

再说ViewModel应该只包含一些简单的判断、检查、打通数据的代码,如果业务过于复杂可以考虑加Presetner,如果真的超级复杂那可以反思下这个复杂的逻辑应不应该放在前端,能不能放在后端呢?

欢迎关注微信公众号《架构文摘》,高质量技术文章第一时间推送。

![](https://img2018.cnblogs.com/blog/585087/201911/585087-20191122153945419-955963416.jpg)

高质量App的架构设计与思考!的更多相关文章

  1. [转]Android App整体架构设计的思考

    1. 架构设计的目的 对程序进行架构设计的原因,归根到底是为了提高生产力.通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点, ...

  2. Android App的架构设计:从VM、MVC、MVP到MVVM

    随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...

  3. 高性能、高可用、高扩展ERP系统架构设计

    ERP之痛 曾几何时,我混迹于电商.珠宝行业4年多,为这两个行业开发过两套大型业务系统(ERP).作为一个ERP系统,系统主要功能模块无非是订单管理.商品管理.生产采购.仓库管理.物流管理.财务管理等 ...

  4. app后端架构设计(转)

    (1)Restful设计原则 Restful风格:RESTfu设计原则,它被Roy Felding提出(在他的”基于网络的软件架构“论文中第五章).而REST的核心原则是将你的API拆分为逻辑上的资源 ...

  5. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  6. APP界面架构设计

    作为PM,信息架构和页面流的设计想必烂熟于心,当确定好产品战略层和范围层即为何种目标用户提供何种服务后,就要着手搭建功能架构,将目标功能通过良好的用户体验传递给用户,目的是高效解决用户痛点,从而实现价 ...

  7. APP系统架构设计初探

    一,图片体验的优化. 在手机上显示图片,速度是一个非常重要的体验点,试想,如果您打开一个网站,发现里面的图片一直显示失败或者是x,稍微做得好一点的,可能是一个不消失的loading或者是菊花等等,但不 ...

  8. 从MySQL高可用引出对高可用架构设计的一些思考

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...

  9. 从mysql高可用架构看高可用架构设计

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...

随机推荐

  1. css3实现饼状图进度及环形进度条

    1 <!-- 饼图 --> <div class="pie"></div> <hr /> <!-- 环形图 --> &l ...

  2. 7.HTTP协议

    1.什么是url? 1.1 URL是统一资源定位符,表示的是一个资源,(图片 文字 视频 音频 等等) 单个资源介绍--图片 那URL的组成部分是由协议, 域名:端口, 路径和文件名 1.2 url组 ...

  3. MyBatis 示例-简介

    简介 为了全面熟悉 MyBatis 的使用,整理一个 MyBatis 的例子,案例中包含了映射器.动态 SQL 的使用.本章先介绍项目结构和配置. 项目地址:链接 数据库表的模型关系:链接 项目结构 ...

  4. config.xml

    ASP.NET应用程序的配置信息都存放于Web.config配置文件中,Web.config配置文件是基于XML格式的文件类型,由于XML文件的可伸缩性,使得ASP.NET应用配置变得灵活.高效.容易 ...

  5. 树莓派上搭建arduino命令行开发环境

    -------------还是博客园上面的格式看这舒服,不去新浪了------------- 为什么要在树莓派上开发arduino呢?总要把树莓派用起来嘛,不然老吃灰. 树莓派使用SSH时没有图形界面 ...

  6. String s=new String("123") 创建了两个对象,及证明

    这个问题百度上有很多答案 有一次面试的时候,面试官也提到了这个问题.我回答了两个对象,并且解释了一个对象是 "123" 存在了字符串常量池,另一个是 s 所引用的堆中的对象. 但是 ...

  7. 彻底解决 Mechanism level: Failed to find any Kerberos tgt

    错误描述 Secure Client Cannot Connect ([Caused by GSSException: No valid credentials provided(Mechanism ...

  8. LHH的acm奋斗史,至强的精神(转载)

    还记得2年前的一个晚上,我和一个女孩一起写完了这篇文章.写完后,她哭了,我笑了.然后,她走了,我哭了.2年后,我又找到她,这次,我没有让她走掉,她成了我的新娘. 不知道什么时候,开始知道ACM:也不知 ...

  9. Bigo的Java面试,我挂在了第三轮技术面上.........

    背景 前段时间家里出了点事,辞职回家待了一段时间,处理完老家的事情后就回到广州这边继续找工作,大概是国庆前几天我去面试了一家叫做Bigo(YY的子公司),面试的职位是面向3-5年的Java开发,最终自 ...

  10. Spring Boot 如何给微信公众号返回消息

    hello 各位小伙伴,今天我们来继续学习如何通过 Spring Boot 开发微信公众号.还没阅读过上篇文章的小伙伴建议先看看上文,有助于理解本文: Spring Boot 开发微信公众号后台 上篇 ...