Android APP研发录

1.1 重新规划android项目结构

类库:

  • utils 公用方法,如对sharePreferences的封装
    项目:
  • Entity 只有属性,上百个的时候,需要考虑按照模块划分
    如果需要业务逻辑的方法的时候,需要转移到Engine这个包的某个类下面。

Activity定义新的生命周期

  • initVariable() 初始化变量,如Intent和Act内的变量
  • initViews() 加载layout布局文件,初始化控件,事件的方法
  • loadData 调用APIMobile获取数据

统一事件编程模型

对于btn的点击事件直接监听,而不是对类来继承接口的监听。然后在对点击事件的逻辑处理进行封装。

1
2
3
4
5
6
7
btnLogin.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
gotoLoginActivity();
}
})

实体化编程

使用fastJson和Gson来解析数据,直接产生实体,而不是使用原生的进行解析。

Adapter模板

继承baseAdapter重写相关的方法,并加入ViewHolder等相关缓存的操作

类型安全转换函数

使用Object.toString()的时候,当objectnull的时候,经常会出现错误。所以,我们需要顶一个专门进行转换的工具类,通过这个工具类使得输出的数据不为null,但转换失败的时候,就输出默认的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final static int convertToInt(Object value, int defaultValue) {
if (value == null || "".equals(value.toString().trim())) {
return defaultValue;
}
try {
return Integer.valueOf(value.toString());
} catch (Exception e) {
try {
return Double.valueOf(value.toString()).intValue();
} catch (Exception e1) {
return defaultValue;
}
}
}

使用原生的ThreadPoolExecutor+Runnable+Handler对网络底层进行封装

使用静态的线程池去执行每一个runnable的网络请求,使用RequestCallBack回调接口去执行对应的成功或者失败的操作,并使用handler去更新UI。

优化工作

  • 通过失败回调的输出信息
  • 将所有连接放在url.xml中,使用时进行加载(为null时候再次加载的做法)

App数据缓存设计

  • 统一交给请求runnable去判断是否进行网络请求?还是读取缓存里面的数据(缓存过期也要进行请求)
  • 加入强制请求,将对应请求时间值设置为0即可。

    使用RequestCallBack

  • 针对缓存信息进行加密,md5加密路径,使用对象流存入文件

MockService的设计

在没有敲定数据协议的情况下,进行离线单机版的请求相应。例子:用户的登录操作

用户登录

  • 存储用户状态信息(自动登录的效果)
  • 登录密码的加密,使用不对称加密(注册的时候存储的是加密后的密码,登录时加密后在发送)
  • 使用cookie作为与服务器对接的登录状态信息,设置过期日期,当过期后统一跳转登录。每次请求都设置cookie在header上,返回就更新cookie的信息。

防黑客盗刷

  • 三次输入失败后验证码
  • 统一ip短时间内频繁访问,返回html5代码,跳转到webview中要求输入验证码。

Http头中的奥妙

  • 通过得到http header中的date时间信息,算出手机与服务器的间隔时间,使得手机客户端无论怎么调整信息后的时间总是和服务器相同。
  • 开启gzip压缩

App图片缓存设计

ImageLoader设计原理

使用软引用,在内存足够时,并不会GC.
显示图片时:内存找->本地磁盘->开新线程下载。

注意三个类:

  • ‰ ‰ImageLoaderConf iguration——对图片缓存进行总体配置,包括内存缓存的大小、本地
    缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等
  • ‰ ‰ImageLoaderConf iguration——对图片缓存进行总体配置,包括内存缓存的大小、本地
    缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等
  • ‰ ‰ImageLoaderConf iguration——对图片缓存进行总体配置,包括内存缓存的大小、本地
    缓存的大小和位置、日志、下载策略(FIFO还是LIFO)等等

优化
记得在每一个基类AppBaseAct中的onDestory()进行clearMemoryCache操作。

图片加载利器Fresco

基于控件级别,需要使用它提供的view进行加载图片。

原理
Fresco有3个线程池,其中3个线程用于网络下载图片,2个线程用于磁盘文件的读写,
还有2个线程用于CPU相关操作,比如图片解码、转换,以及放在后台执行的一些费时操作。

三级缓存设计:
详看:Fresco缓存

网络流量优化

针对非wifi,4G速度快,流量大的优化

通信层面优化

  • 使用gzip进行压缩。注意:大于1KB才进行压缩,否则得不偿失
  • 新的数据传输协议,那就是ProtoBuffer。这种协议基于二进制格式的,所以在表示大数据时,空间比JSON小很多
  • 减少网络访问次数,能调用一次MobileAPI接口就能取到数据的,就不要调用两次
  • 使用HTTP协议的速度远不如使用TCP协议,因为后者是长连接。所以我们可以使用TCP长连接,以提高访问的速度。缺点是一台服务器能支持的长连接个数不多,所以需要更多的服务器集成。
  • 要建立取消网络请求的机制。跳转页面及时取消请求
  • 增加重试机制。比如get请求失败后重试3次。post请求具有防重机制,那么倒是可以增加重试机制。

图片策略优化

  • 在url上添加with和height,解析获取正确的图片大小。
  • 事先在服务器中规定几种规格的图片,利用
    1
    S = (w1-a) ×(w1-w) + (h1-h) ×(h1-h)

找最接近图片尺寸的办法,返回最接近的图片。

  • 低流量模式。在不同的网络模式下,使用url添加参数quality进行返回对应的图片质量
  • 极速模式。不显示图片,仅用默认的图片进行代替。

城市列表的设计

  • 事先在本地集成一定的城市数据。反序列化进行读取数据。
  • 不同版本有不同的数据,需要进行同步。
  • 城市列表数据的增量更新机制。增加一个字段type,来标识改城市是增,删,改的操作。

APP与H5的交互

使用的场景为:当特殊的日子,如双十一/双十二的时候,不必要进行发布来更新对应的活动页,而是用html5进行代替。但使用h5的弊端是,所以需要在原生和h5之间进行取舍。

App和HTML5之间定义跳转协议

HTML5团队需要事先和App团队约定好一个格式:

1
2
3
4
gotoPersonCenter
gotoMovieDetail:movieId=100
gotoNewsList:cityId=1&cityName=北京
gotoUrl:http:// www.sina.com

注意此协议依靠进行划分。

  • 的前面:为key,通过key去寻找对应的跳转类(遍历定义好xml去找对应的包名),进行反射跳转
  • 的后面:为跳转到此activity时,所需要intent传递的参数,并用强制转化来标记不同的数据类型。如下面的实例
1
2
3
<a onclick="baobao.gotoAnyWhere(
'gotoNewsList:cityId=(int)12&cityName=北京')">
gotoAnyWhere</a>

在App中内置HTML5页面

使用wvAds.loadData(realData, "text/html", "utf-8");方法,其中realDatahtml文本。通过自定义realData文本后进行加载html5页面。

注意需要固定的html模板,然后通过模板的节点进行替换对应的值。

灵活切换Native和HTML5页面的策略

我同时做两套页面,Native一套,HTML5
一套,然后在App中设置一个变量,来判断该页面将显示Native还是HTML5的。

通过网络请求的返回值来判断是执行哪个方案。

消灭全局变量(即:static的变量)

场景:当app在后台的时候,全局变量就容易被回收,导致下一次启动,回到原来的界面的时候,全部变量为空,而导致错误

方案

  • 尽可能使用intent来传值,当activity由于内存不足而销毁,但intent保存的数据并不会销毁。但携带数据量过大,也会导致奔溃
  • 对全局变量进行序列化,每次改变完成就序列化到本地,当为空的时候,就从本地获取。

    注意:单例类的序列化,会造成每次序列化产生新的对象,而不是原对象的引用,所以:在单例类加入readResolve()readObject()放发,并实现cloneable接口

    • 第一次启动需要清除序列化全局变量的临时数据
    • 缺点:容易造成ANR,每次都操作磁盘读写,并不是好的解决方案。
    • sharepreference和sqlite都是存储在内存空间上的。

如何保存activity页面状态

通过两个方法:

  • onSaveInstanceState();
  • onRestoreInstanceState();

User是唯一例外的全局变量

通过登录得到,获取必要的信息,用户名,昵称等。

Android命名规范与编码规范

命名规范

分两类:

  • 只在改模块内使用:模块+属性+作用
  • 在整个项目中使用:common+作用

编码规范

eclipse统一格式化代码:
android-formatting.xml

window->preferences->java->code style->formatter导入上面的xml

统一代码规范:
eclipse版本:

android studio版本:
# 代码规范和Android项目中的一些可用工具
# Android Studio配置CheckStyle

第5章 Crash异常手机与统计

使用UncaughtExceptionHandler来处理未捕获的异常。然后将异常发送到服务中。对异常进行分类,去重,讲每个异常指派到不同的人去解决。

第6章 Crash异常分析

下面摘录个人觉得常见的异常:

  • MobileAPI返回脏数据。

    对网络返回的数据的处理,要处理不正确的输出。必要时使用try..catch().

  • 方法需要对传入的参数进行判断空后再使用。
  • 对集合、数组进行判断空,判断长度。
  • 使用subString()一定要判断参数的长度是否正确(0<=start<end
  • 使用类型的转换错误。使用安全类型转换,在catch中进行再次转换成另一种,防止传入数据错误而force close.适当返回默认值
  • 数字转换错误,适当返回默认值
  • 数组长度为-1的情况:new int[args.length-1];这种情况导致。
  • 防止在遍历集合的时候,同时删除其中的元素,应该进行得到后,再一起删除。
  • 使用比较器Comparator的时候,要考虑到=0的情况
  • 使用array.asList()需要注意返回后,是不可以add和remove操作。