源码性能Android知识

Android数据层架构的实现 上篇

2017-05-30  本文已影响752人  何时夕

最近我们app的服务器吃不消了,所以我在为服务器增加缓存层之后,又想到在app端进行二级缓存以减少app对服务器的访问。我想很多app应该在项目的初期架构的时候就考虑到了这个问题,但是我当时开发这个app的时候完全不懂架构和设计模式,所以对性能根本没有考虑,导致了现在服务器经常崩溃。关于服务器的优化之后有时间再说,今天我们先来看看如何对一个app的数据的请求和缓存进行架构。

一.数据请求的分类、数据的可缓存性分析和数据同步##

如何对请求进行归类?这是个问题,在Http请求里设定了八种请求的方式,但是显然并不适合我们这里的情况。我对我们app中的数据请求进行归类之后进行了一下两种分类

什么样的数据更适合在本地进行缓存呢?

前面我们说了两类可以在本地进行缓存的数据表,那么这两类数据该如何与服务器同步?

二、数据引擎的设计模式##

分析了上面的三个问题之后,我们得想想要使用什么样的方法来设计我们的数据引擎,熟悉java设计模式的同学可能会想到很多东西。我最近看了 Android源码设计模式解析与实战 之后也了解到了许多设计模式,现在的问题是怎么用这些设计模式呢?还好我最近又翻译了Fresco和OkHttp的源码,所以可以从这两个牛逼的开源项目中吸取一点经验。

三、具体代码实现##

务虚了这么久,也应该务实了。先上项目例子数据引擎架构项目源码,建议大家下载过来,然后结合博客一起观看下面我来分析一下数据引擎架构的实现代码。

1.请求和返回类设计

我们可以将所有的数据请求,当成类似于网络请求的格式。这样一来我们可以创建两个类一个Request,一个Response供客户端使用

public class Request {

private static final String TAG="Request";
private static final Object RECYCLER_LOCK = new Object();
private static int MAX_RECYCLED = 5;
private static Request sFirstRecycledRequest;
private static int sRecycledCount;

private Request mNextRecycledRequest;

@NonNull
private RequestFlag mRequestFlag;
@NonNull
private CacheKey mCacheKey;
@Nullable
private Object mParam;
private boolean isCacheToMemory=true;
private boolean isSaveToLocal=true;
private boolean[] interceptorIsEnable=new boolean[]{true,true,true,true,true,true,true,true,true};

public static Request setFlag(@NonNull RequestFlag requestFlag){
    return obtain(requestFlag,null,null,null,-1);
}

public static Request setFlagParam(@NonNull RequestFlag requestFlag, @NonNull Object param){
    return obtain(requestFlag,param,null,null,-1);
}

public static Request setFlagParamKey(@NonNull RequestFlag requestFlag, @NonNull Object param, @NonNull String key){
    return obtain(requestFlag,param,key,null,-1);
}

public static Request setFlagParamInterceptorIsEnable(@NonNull RequestFlag requestFlag, @NonNull Object param, @NonNull boolean[] interceptorIsEnable){
    return obtain(requestFlag,param,null,interceptorIsEnable,-1);
}

public static Request setFlagParamWhichServiceUnable(@NonNull RequestFlag requestFlag, @NonNull Object param, int whichUnable){
    return obtain(requestFlag,param,null,null,whichUnable);
}

public void recycle() {
    synchronized (RECYCLER_LOCK) {
        if (sRecycledCount < MAX_RECYCLED) {
            reset();
            sRecycledCount++;

            if (sFirstRecycledRequest != null) {
                mNextRecycledRequest= sFirstRecycledRequest;
            }
            FLog.v(TAG,"回收Request  sRecycledCount:"+sRecycledCount);
            sFirstRecycledRequest= this;
        }
    }
}

private static Request obtain(@NonNull RequestFlag requestFlag, Object param, String key, boolean[] interceptorIsEnable, int whichUnable) {
    synchronized (RECYCLER_LOCK) {
        if (sFirstRecycledRequest!= null) {
            Request requestToReuse = sFirstRecycledRequest;
            sFirstRecycledRequest= requestToReuse.mNextRecycledRequest;
            requestToReuse.mNextRecycledRequest= null;

            requestToReuse.mRequestFlag=requestFlag;
            if (param==null){
                requestToReuse.mCacheKey=new SimpleCacheKey(requestFlag.toString());
            }else {
                requestToReuse.mParam=param;
                if (key!=null){
                    requestToReuse.mCacheKey = new SimpleCacheKey(key);
                }else {
                    requestToReuse.mCacheKey=new SimpleCacheKey(JsonUtil.objectToJson(param));
                    if (interceptorIsEnable!=null) {
                        requestToReuse.interceptorIsEnable = interceptorIsEnable;
                    }else {
                        if (whichUnable!=-1)requestToReuse.interceptorIsEnable[whichUnable]=false;
                    }
                }
            }
            sRecycledCount--;
            FLog.v(TAG,"从对象池中获取Request  sRecycledCount:"+sRecycledCount);
            return requestToReuse;
        }
    }
    FLog.v(TAG,"对象池已空,创建一个Request  sRecycledCount:"+sRecycledCount);
    if (param==null){
        return new Request(requestFlag);
    }else {
        if (key!=null){
            return new Request(requestFlag,param,key);
        }else {
            if (interceptorIsEnable!=null) {
                return new Request(requestFlag,param,interceptorIsEnable);
            }else {
                if (whichUnable==-1){
                    return new Request(requestFlag,param);
                }else {
                    return new Request(requestFlag,param,whichUnable);
                }
            }
        }
    }
}

private void reset() {
    mRequestFlag=null;
    mCacheKey=null;
    mParam=null;
    isCacheToMemory=true;
    isSaveToLocal=true;
    interceptorIsEnable=new boolean[]{true,true,true,true,true,true,true,true,true};
}

private Request() {
}

private Request(@NonNull RequestFlag requestFlag) {
    mRequestFlag = requestFlag;
    mCacheKey=new SimpleCacheKey(mRequestFlag.toString());
}

private Request(@NonNull RequestFlag requestFlag, @Nullable Object param) {
    mRequestFlag = requestFlag;
    mParam = param;
    mCacheKey=new SimpleCacheKey(JsonUtil.objectToJson(param));
}

private Request(@NonNull RequestFlag requestFlag, @Nullable Object param, boolean[] interceptorIsEnable) {
    mRequestFlag = requestFlag;
    mParam = param;
    this.interceptorIsEnable = interceptorIsEnable;
    mCacheKey=new SimpleCacheKey(JsonUtil.objectToJson(param));
}

private Request(@NonNull RequestFlag requestFlag, @Nullable Object param, int whichUnable) {
    mRequestFlag = requestFlag;
    mParam = param;
    interceptorIsEnable[whichUnable]=false;
    mCacheKey=new SimpleCacheKey(JsonUtil.objectToJson(param));
}

private Request(@NonNull RequestFlag requestFlag, @Nullable Object param, String key) {
    mCacheKey = new SimpleCacheKey(key);
    mRequestFlag = requestFlag;
    mParam = param;
}

public Request setParam(@Nullable Object param) {
    this.mParam = param;
    return this;
}

public Request setRequestFlag(@NonNull RequestFlag requestFlag) {
    mRequestFlag = requestFlag;
    return this;
}

public Request setServiceIsEnable(int serviceNum, boolean isEnable) {
    if (serviceNum<interceptorIsEnable.length)interceptorIsEnable[serviceNum]=isEnable;
    return this;
}

public Request setInterceptorIsEnable(boolean[] interceptorIsEnable) {
    this.interceptorIsEnable = interceptorIsEnable;
    return this;
}

public boolean getWhichServiceIsEnable(int serviceNum) {
    return serviceNum < interceptorIsEnable.length && interceptorIsEnable[serviceNum];
}

public Request setCacheKey(@NonNull CacheKey cacheKey) {
    mCacheKey = cacheKey;
    return this;
}

public Request setCacheToMemory(boolean cacheToMemory) {
    isCacheToMemory = cacheToMemory;
    return this;
}

public Request setSaveToLocal(boolean saveToLocal) {
    isSaveToLocal = saveToLocal;
    return this;
}

public boolean[] getInterceptorIsEnable() {
    return interceptorIsEnable;
}

@Nullable
public Object getParam() {
    return mParam;
}

@NonNull
public RequestFlag getRequestFlag() {
    return mRequestFlag;
}

@NonNull
public CacheKey getCacheKey() {
    return mCacheKey;
}

public boolean isCacheToMemory() {
    return isCacheToMemory;
}

public boolean isSaveToLocal() {
    return isSaveToLocal;
}

@Override
public String toString() {
    return "Request:{" +
            "mCacheKey=" + mCacheKey +
            ", mRequestFlag=" + mRequestFlag +
            ", mParam=" + mParam +
            ", isCacheToMemory=" + isCacheToMemory +
            ", isSaveToLocal=" + isSaveToLocal +
            ", interceptorIsEnable=" + Arrays.toString(interceptorIsEnable) +
            '}';
}
}

public class Response<Response1,Response2 ,Response3> {

private boolean isSuccess;
private Exception mException;

private Response1 mResponse1;
private Response2 mResponse2;
private Response3 mResponse3;

public static <T1,T2,T3> Response<T1,T2,T3>  getFailedResponse(Exception exception){
    return new Response<T1,T2,T3>(false,exception);
}

public static Response getCommonResponseOne(Object response1){
    return new Response<Object,Object,Object>(response1);
}

public static Response getCommonResponseTwo(Object response1,Object response2){
    return new Response<Object,Object,Object>(response1,response2);
}

public static Response getCommonResponseThree(Object response1,Object response2,Object response3){
    return new Response<Object,Object,Object>(response1,response2,response3);
}

public static <T> Response getResponseOne(T response1){
    return new Response<T,Object,Object>(response1);
}

public static <T1,T2> Response getResponseTwo(T1 response1,T2 response2){
    return new Response<T1,T2,Object>(response1);
}

public static <T1,T2,T3> Response getResponseOne(T1 response1,T2 response2,T3 response3){
    return new Response<T1,T2,T3>(response1,response2,response3);
}

private Response(boolean isSuccess, Exception exception) {
    this.isSuccess = isSuccess;
    mException = exception;
}

private Response(Response1 response1) {
    mResponse1 = response1;
    isSuccess=true;
}

private Response(Response1 response1, Response2 response2) {
    mResponse1 = response1;
    mResponse2 = response2;
    isSuccess=true;
}

private Response(Response1 response1, Response2 response2, Response3 response3) {
    mResponse1 = response1;
    mResponse2 = response2;
    mResponse3 = response3;
    isSuccess=true;
}

public Response1 getResponse1() {
    return mResponse1;
}

public void setResponse1(Response1 response1) {
    mResponse1 = response1;
}

public Response2 getResponse2() {
    return mResponse2;
}

public void setResponse2(Response2 response2) {
    mResponse2 = response2;
}

public Response3 getResponse3() {
    return mResponse3;
}

public void setResponse3(Response3 response3) {
    mResponse3 = response3;
}

public boolean isSuccess() {
    return isSuccess;
}

public Exception getException() {
    return mException;
}
}

2.拦截链的骨架

我们在前面的设计模式中提到了,在设计一个架构的时候需要面向接口编程,这样才会符合前面说的设计模式六大原则。

public interface Interceptor {
Object intercept(Chain chain,boolean enable) throws Exception;

Service getService();
interface Chain {
    Object proceed() throws Exception;

    Request getRequest();
}
}   

public interface Service {
boolean isEnabled();

void setEnable(boolean enable);

Object in(Request request, Object in) throws Exception;

Object out(Request request) throws Exception;
}

3.拦截器链和拦截器的实现

我实现了四个拦截器:内存缓存拦截器-->新线程拦截器-->硬盘储存拦截器-->网络请求拦截器。和一个拦截器链,这个链中使用了上面四个拦截器。

public class RealInterceptorChain implements Interceptor.Chain {

public static String TAG="RealInterceptorChain";
private static final Object RECYCLER_LOCK = new Object();
private static int MAX_RECYCLED = 5;
private static RealInterceptorChain sFirstRecycledChain;
private static int sRecycledCount;

private RealInterceptorChain mNextRecycledChain;

private Request mRequest;
private final List<Interceptor> interceptors;
private int index=0;

private RealInterceptorChain(Request request) {
    mRequest=request;
    this.interceptors = DataEngine.mInterceptors;
}

@Override
public Object proceed() throws Exception {
    if (index >= interceptors.size()){
        throw new AssertionError();
    }
    Interceptor interceptor = interceptors.get(index);
    boolean isEnable=mRequest.getInterceptorIsEnable()[index];
    index++;
    return interceptor.intercept(this,isEnable);
}

@Override
public Request getRequest() {
    return mRequest;
}

public void recycle() {
    synchronized (RECYCLER_LOCK) {
        if (sRecycledCount < MAX_RECYCLED) {
            reset();
            sRecycledCount++;

            if (sFirstRecycledChain != null) {
                mNextRecycledChain = sFirstRecycledChain;
            }
            sFirstRecycledChain = this;
            FLog.v(TAG,"回收Chain  sRecycledCount:"+sRecycledCount);
        }
    }
}

public static RealInterceptorChain obtain(Request request) {
    synchronized (RECYCLER_LOCK) {
        if (sFirstRecycledChain != null) {
            RealInterceptorChain eventToReuse = sFirstRecycledChain;
            sFirstRecycledChain = eventToReuse.mNextRecycledChain;
            eventToReuse.mNextRecycledChain = null;
            eventToReuse.mRequest=request;
            sRecycledCount--;
            FLog.v(TAG,"从对象池中获取Chain  sRecycledCount:"+sRecycledCount);
            return eventToReuse;
        }
    }
    FLog.v(TAG,"对象池已空,创建一个Chain  sRecycledCount:"+sRecycledCount);
    return new RealInterceptorChain(request);
}

private void reset() {
    mRequest = null;
    index=0;
}
}

@Immutable

public class MemoryCacheInterceptor implements Interceptor {

public static String TAG="MemoryCacheInterceptor";
private final Service memoryCacheService;

public MemoryCacheInterceptor(Service memoryCacheService) {
    this.memoryCacheService = memoryCacheService;
}

@Override
public Object intercept(final Chain chain, boolean enable) throws Exception {
    final Request request=chain.getRequest();
    Object response = null;
    boolean isEnable=enable&&getService().isEnabled();
    RequestFlag requestFlag= request.getRequestFlag();
    FLog.v(TAG,request.getRequestFlag().toString()+"请求进入");

    if (requestFlag.getRequestLevel()==RequestLevel.to_memory){
        //在这种情况下,如果不开启内存缓存,那么就直接返回null
        if (!isEnable) response=null;
        switch (requestFlag.getRequestType()){
            case GET:
                //返回内存缓存中的结果
                response= memoryCacheService.out(request);
                break;
            case INSERT:
                //在更新内存缓存之后,返回更新后的结果
                response= memoryCacheService.in(request,null);
                break;
            case NONE:
                //在memory下,不会有这种请求
                response= null;
                break;
        }
    }else {
        boolean isNeedToNextService=true;
        switch (requestFlag.getRequestType()){
            case GET:
                if (isEnable){
                    //内存缓存服务可以使用,就使用他
                    response= memoryCacheService.out(request);
                    //如果从内存缓存中获取的结果不为null,那么就不需要去下一个服务取数据
                    if (response!=null)isNeedToNextService=false;
                }
                //这里不用 break 可以直接在需要进入下一个服务的情况下,复用代码。
            case INSERT:
                // 如果请求是GET,表示从内存中获取的结果是null,所以需要进入下一个服务获取数据
                // 如果请求是INSERT 由于这种请求肯定要经过下一个服务,所以不需要判断本服务是否可用
                // 下一个服务开始要去本地或者网络获取数据了,所以返回的是 Observable
                if (isNeedToNextService)
                    response= ((Observable<?>)chain.proceed())
                            .map(new Func1<Object, Object>() {
                            @Override
                            public Object call(Object o) {
                                //如果回调后的结果不是null并且允许该数据被缓存(默认是允许的,除非在下一个服务返回的时候禁止了),就缓存这个结果
                                if (o != null && request.isCacheToMemory())try {
                                    memoryCacheService.in(request, o);
                                } catch (Exception e) {
                                    //此时是 内存缓存的存储出了问题
                                    FLog.e(TAG, "内存缓存的存储出了问题", e);
                                    return Response.getFailedResponse(e);
                                }
                                return o;
                            }
                        });
                break;
            case NONE:
                //这种请求直接进入下一个服务,下一个服务开始要去本地或者网络获取数据了,所以返回的是 Observable
                response= chain.proceed();
                break;
        }
    }
    FLog.v(TAG,request.getRequestFlag().toString()+"  "+TAG+"返回");
    return response;
}

@Override
public Service getService() {
    return memoryCacheService;
}

}

@Immutable

public class NewThreadInterceptor implements Interceptor {
public static String TAG="NewThreadInterceptor";

@Override
public Observable<Object> intercept(final Chain chain, boolean enable)  {
    return Observable.just(chain)
            .observeOn(Schedulers.io())
            .map(new Func1<Chain, Object>() {
                @Override
                public Object call(Chain chain) {
                    try {
                        return chain.proceed();
                    } catch (Exception e) {
                        //此时是本地存储或者网络请求出了问题
                        FLog.e(TAG,"本地存储或者网络请求出了问题",e);
                        return Response.getFailedResponse(e);
                    }
                }
            });
}

@Override
public Service getService() {
    return null;
}
}

@Immutable

public class LocalDataInterceptor implements Interceptor {
public static String TAG="LocalDataInterceptor";
private final Service localDataService;

public LocalDataInterceptor(Service localDataService) {
    this.localDataService = localDataService;
}

@Override
public Object intercept(Chain chain,boolean enable) throws Exception {
    final Request request=chain.getRequest();
    Object response = null;
    boolean isEnable=enable&&getService().isEnabled();
    RequestFlag requestFlag= request.getRequestFlag();
    FLog.v(TAG,request.getRequestFlag().toString()+"请求进入");

    if (requestFlag.getRequestLevel()==RequestLevel.to_local){
        //在这种情况下,如果不开启本地数据服务,那么就直接返回null
        if (!isEnable)return null;
        switch (requestFlag.getRequestType()){
            case GET:
                //返回本地数据中的结果
                response= localDataService.out(request);
                break;
            case INSERT:
                //在更新内存缓存之后,返回更新后的结果
                response= localDataService.in(request,null);
                break;
            case NONE:
                //根据传入的信息和内存缓存中的信息,经过验证操作后,验证返回结果
                response= localDataService.in(request,null);
                break;
        }
    }else {
        boolean isNeedToNextService=true;
        switch (requestFlag.getRequestType()){
            case GET:
                if (isEnable) {
                    //本地存储服务可以使用,就使用他
                    response = localDataService.out(request);
                    //如果从本地储存中获取的结果不为null,那么就不需要去下一个服务取数据
                    if (response != null) isNeedToNextService = false;
                    //这里不用 break 可以直接在需要进入下一个服务的情况下,复用代码。
                }
            case INSERT:
                // 如果请求是GET,表示从本地获取的结果是null,所以需要进入下一个服务获取数据
                // 如果请求是INSERT 由于这种请求肯定要经过下一个服务,所以不需要判断本服务是否可用
                if (isNeedToNextService){
                    response= chain.proceed();
                    //如果下一个服务取来的结果不是null,并且这个数据被允许存在本地(默认是允许的,除非在下一个服务返回的时候禁止了),,就把这个结果存起来
                    if (response!=null&&request.isSaveToLocal()) localDataService.in(request,response);
                }
                break;
            case NONE:
                //由于这种请求肯定要经过下一个服务,所以不需要判断本服务是否可用,也不需要将返回的结果存在本地
                response= chain.proceed();
                break;
        }
    }
    FLog.v(TAG,request.getRequestFlag()+"  "+TAG+"返回");
    return response;
}

@Override
public Service getService() {
    return localDataService;
}
}

@Immutable

public class NetworkInterceptor implements Interceptor{
public static String TAG="NetworkInterceptor";

private final Service mNetworkService;

public NetworkInterceptor(Service networkService) {
    this.mNetworkService = networkService;
}

@Override
public Object intercept(Chain chain,boolean enable) throws Exception {
    final Request request=chain.getRequest();
    boolean isEnable=enable&&getService().isEnabled();
    FLog.v(TAG,request.getRequestFlag().toString()+"请求进入");
    //如果网络服务不可用,就返回null
    if (!isEnable)return null;
    Object response=mNetworkService.out(chain.getRequest());
    FLog.v(TAG,request.getRequestFlag().toString()+"  "+TAG+"返回");
    return response;
}

@Override
public Service getService() {
    return mNetworkService;
}
}

整个拦截器链的实现就是上面这样,可以看出虽然我并没有讲解各个拦截器中的服务具体是怎么实现的,但是这并不影响整个拦截器链的逻辑。由于我们定义了Service这个抽象的接口,我们在拦截器链的实现过程中,并不需要去在意Service的具体逻辑,这就是将拦截器和服务解耦,而一旦解耦了,Service的实现类中无论如何变化,都影响不到整个拦截器链的框架。

由于字数太多:所以分成了两篇:Android数据层架构的实现 下篇

上一篇 下一篇

猜你喜欢

热点阅读