读书笔记App研发录--数据缓存设计

读书笔记App研发录–数据缓存设计

标签(空格分隔): 数据缓存 android 优化


数据缓存策略

在2G和3G网络状态下,MobileApi访问速度过慢,会导致不好的用户体验。网络端的数据接受的限制主要是传输速度的限制。
策略

  • 减少MobileApi的调用次数
  • App缓存时间。分时间段调用,一段时间使用缓存数据

App缓存只使用于数据即时性要求不高的数据。当然也可以根据具体的需求调节App缓存时间

即使对于同一个MobileApi,传入的参数不同,缓存也应该是不同的

最简单的时间参数,在不同的时间获取的天气情况,date=A和date=B 应该分别对应两个缓存数据。不能存放在一起。

缓存位置

  • SD卡

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);
            }
    }

你可能感兴趣的:(读书笔记)