标签(空格分隔): 数据缓存 android 优化
在2G和3G网络状态下,MobileApi访问速度过慢,会导致不好的用户体验。网络端的数据接受的限制主要是传输速度的限制。
策略
App缓存只使用于数据即时性要求不高的数据。当然也可以根据具体的需求调节App缓存时间
即使对于同一个MobileApi,传入的参数不同,缓存也应该是不同的
最简单的时间参数,在不同的时间获取的天气情况,date=A和date=B 应该分别对应两个缓存数据。不能存放在一起。
App数据缓存较大,在内存中极易被GC回收。
数据缓存应该在网络层完成
a) url.xml中为每一个MobileApi接口配置缓存时间Expired,对于Post,一律设置为0
public class URLData {
private String key;
private long expires; // 配置时间
private String netType;
private String url;
private String mockClass;
}
b) 写一个排序算法sortKets,对URL中的key进行排序
void sortKeys() {
for (int i = 1; i < parameter.size(); i++) {
for (int j = i; j > 0; j--) {
RequestParameter p1 = parameter.get(j - 1);
RequestParameter p2 = parameter.get(j);
if (compare(p1.getName(), p2.getName())) {
// 交互p1和p2这两个对象,写的超级恶心
String name = p1.getName();
String value = p1.getValue();
p1.setName(p2.getName());
p1.setValue(p2.getValue());
p2.setName(name);
p2.setValue(value);
}
}
}
}
// 返回true说明str1大,返回false说明str2大
boolean compare(String str1, String str2) {
String uppStr1 = str1.toUpperCase();
String uppStr2 = str2.toUpperCase();
boolean str1IsLonger = true;
int minLen = 0;
if (str1.length() < str2.length()) {
minLen = str1.length();
str1IsLonger = false;
} else {
minLen = str2.length();
str1IsLonger = true;
}
for (int index = 0; index < minLen; index++) {
char ch1 = uppStr1.charAt(index);
char ch2 = uppStr2.charAt(index);
if (ch1 != ch2) {
if (ch1 > ch2) {
return true; // str1大
} else {
return false; // str2大
}
}
}
return str1IsLonger;
}
c ) 将newUrl作为新key,检查是否存在缓存数据,有,返回
if (urlData.getExpires() > 0) {
final String content = CacheManager.getInstance()
.getFileCache(newUrl);
if (content != null) {
handler.post(new Runnable() {
@Override
public void run() {
requestCallback.onSuccess(content);
}
});
return;
}
}
d )否则继续调用MobileApi从网络端获取数据,并存入缓存
{
// 把成功获取到的数据记录到缓存
if (urlData.getNetType().equals(REQUEST_GET)
&& urlData.getExpires() > 0) {
CacheManager.getInstance().putFileCache(newUrl,
responseInJson.getResult(),
urlData.getExpires());
}
handler.post(new Runnable() {
@Override
public void run() {
requestCallback.onSuccess(responseInJson
.getResult());
}
});
// 保存Cookie
saveCookie();
}
e )其中CacheManager的putFileCache()完成了数据的唯一性操作(MD5)
public void putFileCache(final String key, final String data,
long expiredTime) {
String md5Key = BaseUtils.getMd5(key); // 根据Url产生唯一的MD5
final CacheItem item = new CacheItem(md5Key, data, expiredTime);
putIntoCache(item);
}
f )MD5加密的实现
public static String getMd5(final String s)
{
try
{
// Create MD5 Hash
final MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.trim().getBytes());
final byte messageDigest[] = digest.digest();
return BaseUtils.toHexString(messageDigest);
}
catch (final NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return s;
}
/**
* 转换为十六进制字符串
*
* @param b
* byte数组
* @return String byte数组处理后字符串
*/
public static String toHexString(final byte[] b)
{// String to byte
final StringBuilder sb = new StringBuilder(b.length * 2);
for (final byte element : b)
{
sb.append(BaseUtils.HEX_DIGITS[(element & 0xf0) >>> 4]);
sb.append(BaseUtils.HEX_DIGITS[element & 0x0f]);
}
return sb.toString();
}
g )最后将可序列化的Object类型,序列化到本地
public static final void saveObject(String path, Object saveObject) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
File f = new File(path);
try {
fos = new FileOutputStream(f);
oos = new ObjectOutputStream(fos);
oos.writeObject(saveObject);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在RemoteService暴露出一个boolean类型的参数,用于判断是否要遵从App端的缓存缓存策略,如果是,则在从url.xml中读数据的时候(UrlData实体),将其expired强制设置为0。
public void invoke(final BaseActivity activity,
final String apiKey,
final List params,
final RequestCallback callBack
final boolean forceUpdate) {
if(forceUpdate) {
urlData.setExpires(0);
}
}