天天看點

Android資料層架構的實作 下篇

接上篇: Android資料層架構的實作 上篇

4.外觀模式實作資料處理引擎架構暴露出來的api

我們在使用各種開源架構的時候,大多數時候都不會對架構内部的實作進行細究,是以一個好的架構需要一個簡單的入口來對整個架構進行使用,我接下來就是要講解本架構的入口類。
public class DataEngine {
public static String TAG="DataEngine";
public static Context nowContext;
public static ObservableBoolean nowIsShowProgressBar;

public static final List<Interceptor> mInterceptors=new ArrayList<>();
public static final DataEngine sInstance;
static  {
    synchronized (DataEngine.class){
        sInstance=new DataEngine();
    }
}

private final Service memoryCacheService=new MemoryCacheServiceImpl(true);
private final Service mLocalDataService =new LocalDataServiceImpl(true) ;
private final Service networkService=new NetworkServiceImpl(true);
private DataEngine() {
    mInterceptors.add(new MemoryCacheInterceptor(memoryCacheService));
    mInterceptors.add(new NewThreadInterceptor());
    mInterceptors.add(new LocalDataInterceptor(mLocalDataService));
    mInterceptors.add(new NetworkInterceptor(networkService));
}

/**
 * 所有的資料請求,都是從這個方法開始。本方法在{@link LocalDataEngine}和{@link NetworkDataEngine}中使用。
 * @param request 傳入的資料請求
 * @return
 */
public Observable<Response> request(final Request request){
    final RealInterceptorChain realInterceptorChain=RealInterceptorChain.obtain(request);
    Object response;
    try {
        response = realInterceptorChain.proceed();
    } catch (Exception e) {
        e.printStackTrace();
        // 此時抛出的異常,那麼就是請求失敗了,應該是記憶體緩存服務有問題,由于發生了未知的錯誤是以不應該繼續運作這個請求了。
        FLog.e(TAG,"應該是記憶體緩存服務有問題",e);
        return Observable.just(Response.getFailedResponse(e))
                .compose(((RxAppCompatActivity)nowContext).<Response>bindToLifecycle())
                .filter(new Func1<Response, Boolean>() {
                    @Override
                    public Boolean call(Response appConfigObjectObjectResponse) {
                        //此時攔截鍊已經調用完畢,是以可以将RealInterceptorChain回收
                        realInterceptorChain.recycle();
                        Toast.makeText(nowContext, "操作失敗,發生未知錯誤", Toast.LENGTH_SHORT).show();
                        if (nowIsShowProgressBar!=null)nowIsShowProgressBar.set(false);
                        return appConfigObjectObjectResponse.isSuccess();
                    }
                });
    }

    Observable<?> finalResponseObservable;
    if (response instanceof Observable){
        // 這裡表示需要從其他線程擷取資料資料,一般是本地儲存或者網絡上的資料
        finalResponseObservable = (Observable<?>) response;
    } else {
        // 這裡表示直接從本線程擷取資料,一般是記憶體中的資料
        finalResponseObservable = Observable.just(response);
    }
    return finalResponseObservable
            .compose(((RxAppCompatActivity)nowContext).bindToLifecycle())
            .observeOn(AndroidSchedulers.mainThread())
            .filter(new Func1<Object, Boolean>() {
                @Override
                public Boolean call(Object o) {
                    //此時攔截鍊已經調用完畢,是以可以将RealInterceptorChain回收
                    realInterceptorChain.recycle();
                    if (o instanceof Response){
                        // 這裡表示在 本地儲存或者網絡請求或者想記憶體緩存存資料的時候 發生了問題,是以直接傳回了請求錯誤的結果,
                        // 由于發生了未知的錯誤是以不應該繼續運作這個請求了。
                        Toast.makeText(nowContext, "操作失敗,發生未知錯誤", Toast.LENGTH_SHORT).show();
                        if (nowIsShowProgressBar!=null)nowIsShowProgressBar.set(false);
                        return ((Response) o).isSuccess();
                    }
                    return true;
                }
            }).map(new Func1<Object, Response>() {
                @Override
                public Response call(Object o) {
                    FLog.v(TAG, request.getRequestFlag()+"請求成功");
                    FLog.v("                                         ","                                     ");
                    return Response.getCommonResponseOne(o);
                }
            });
}
}
           

由于本架構适配了Rxjava,是以需要大家對Rxjava比較熟悉

  • 1.前三個靜态變量不需要細究,List<Interceptor> mInterceptors是靜态final變量,在DataEngine單例建立的時候會把攔截器放入其中。DataEngine sInstance是靜态final單例,使用同步的方式在類被加載的時候初始化,由于DataEngine的構造器是private的,是以這個類不能再建立其他對象了。
  • 2.我們由代碼可以看出,所有的Service和List<Interceptor> mInterceptors都是被多線程共用的,是以此時就會出現線程安全問題。由于mInterceptors中的攔截器都是不可變類,是以這個不需要擔心。但是所有Service的實作就需要對某些操作進行同步了,Service的實作和同步會在後面講到。
  • 3.再下來我們就可以看見,惟一一個public的方法request(final Request request):
    • 1.方法首先會去RealInterceptorChain的對象池中擷取一個對象,然後調用realInterceptorChain#proceed()擷取結果。注意這裡的調用都是在主線程進行的,如果大家對前面的MemoryCacheInterceptor還有印象的話,就會知道這裡要麼傳回資料類Object,要麼傳回一個Observable。資料類Object是從記憶體中擷取的不會在其他線程,而Observable并沒有調用subscribe(),是以其隻是對一個請求的封裝,真正的請求還沒被調用。
    • 2.在擷取到response之後,要判斷這個response到底是資料類Object還是Observable,如果是資料類Object将其再用Observable封裝。
    • 3.再進行了上面的操作之後,傳回的請求就都變成Observable了,此時我們先将線程切換為主線程,然後用一個filter過濾掉出現異常的請求,最後将成功擷取的資料映射成一個Response。注意:此時傳回的是Observable,真正的調用會由用戶端觸發

5.服務的實作

前面我們在講攔截鍊的時候,使用的都是Service接口,那麼每個攔截器的具體實作是怎麼樣的呢?接下來我就來講解一下我們app登入時,每個服務的實作。

@ThreadSafe

public class MemoryCacheServiceImpl implements Service{
private final MemoryCache<CacheKey,Object> mainMemoryCache=new CountingLruMapMemoryCacheImpl<CacheKey, Object>(200,new DefaultCacheListener());
private final MemoryCache minorMemoryCache=null;
private boolean enable;

public MemoryCacheServiceImpl(boolean enable) {
    this.enable = enable;
}

@Override
public Object in(Request request, Object in) throws Exception {
    return mainMemoryCache.cache(request.getCacheKey(),in==null?request.getParam():in);
}

@Override
public Object out(Request request) throws Exception {
    return mainMemoryCache.get(request.getCacheKey());
}

@Override
public boolean isEnabled() {
    return enable;
}

@Override
public void setEnable(boolean enable) {
    this.enable=enable;
}

}
           
  • 1.MemoryCacheServiceImpl是記憶體服務的實作類。
      1. MemoryCache<CacheKey,Object> mainMemoryCache:是一個接口,由于我們可以使用第三方類庫實作緩存,也可以寫一個自制緩存,如果在記憶體緩存服務中使用實際的類,那麼在以後要進行更換記憶體緩存實作的時候就需要改動很多地方。而MemoryCache<CacheKey,Object>就是我定義了一組記憶體緩存元件的标準,隻要實作了這個标準的記憶體緩存元件都能用于這個記憶體緩存服務。
    • 2.MemoryCache minorMemoryCache:是副緩存,目前沒有指派。
    • 3.接下來的四個方法就是對Service的實作,可以看見對于in()代碼中就直接調用的是緩存元件的cache()來對,傳入的參數或者傳回的結果進行緩存。out()中就是直接從緩存元件中根據Request中的CacheKey擷取緩存的資料。
    代碼
    public interface ToLocalDataRequest<OUT,IN> {
                  OUT updateAndGetAppConfig(Request request, IN in)throws Exception;
                  OUT getAppConfig(Request request, IN in)throws Exception ;
                  OUT updateAndGetUserConfig(Request request, IN in) throws Exception;
                  OUT getUserConfig(Request request, IN in)throws Exception ;
          }
          public interface ToNetworkRequest<OUT,IN> {
             OUT patrolAccountAction_login(Request request, IN in)throws Exception ;
              OUT initAppData(Request request, IN in)throws Exception ;
          }
               
  • 2.在講本地儲存服務和網絡服務的時候,先來介紹兩個接口。ToLocalDataRequest<OUT,IN>和ToNetworkRequest<OUT,IN>。我們都知道記憶體緩存中存取資料是比較簡單的,但是到了硬碟和伺服器上就不一樣了。有時我們會用資料庫實作硬碟緩存,有時候會用檔案系統實作硬碟緩存,在這個時候對于不同種類的請求要進行的操作是不同的,同樣對于向伺服器的請求也是一樣的。是以我們需要對本地存儲請求和伺服器請求分别建立接口,然後讓本地存儲服務和網絡請求服務去實作他們,最後根據不同的請求來調用不同的被覆寫的方法。
public class LocalDataServiceImpl implements Service,ToLocalDataRequest,ToNetworkRequest{
private static String TAG="LocalDataServiceImpl";

private final DaoMaster daoMaster = new DaoMaster(new DaoMaster.DevOpenHelper(MyApplication.myApplication, "my.db", null).getWritableDb());
private final DiskCache<SimpleCacheKey> sharePreferenceDiskCache =new SharePreferenceDiskCacheImpl<>(MyApplication.myApplication,new DefaultCacheListener());
private boolean enable;

public LocalDataServiceImpl(boolean enable) {
    this.enable = enable;
}

@Override
public Object in(Request request,Object in) throws Exception {
    return TransformDataMethodDispatch.dispatch(this,this,request,in);
}

@Override
public Object out(Request request) throws Exception {
    return TransformDataMethodDispatch.dispatch(this,this,request,null);
}

@Override
public Object patrolAccountAction_login(Request request, Object in) throws IOException {
    return null;
}

@Override
public Object initAppData(Request request, Object in) throws IOException {
    if (in==null)return null;
    FlushData flushData=(FlushData)in;
    ArrayList<MissionInfoEntity> mInfoEntityArrayList=flushData.getFlushData().getInfoEntityArrayList();
    ArrayList<PolicePeopleEntity> mPeopleArrayList=flushData.getFlushData().getPeopleArrayList();
    ArrayList<UnitBaseEntity> mUnitBaseArrayList=flushData.getFlushData().getUnitBaseArrayList();

    if (mInfoEntityArrayList!=null&&mInfoEntityArrayList.size()!=0){
        for (MissionInfoEntity m:mInfoEntityArrayList){
            daoMaster.newSession().getMissionInfoDao().insert(new MissionInfo(m));
        }
    }

    if (mPeopleArrayList!=null&&mPeopleArrayList.size()!=0){
        for (PolicePeopleEntity p :mPeopleArrayList){
            daoMaster.newSession().getPolicePeopleDao().insert(new PolicePeople(p));
        }
    }

    if (mUnitBaseArrayList!=null&&mUnitBaseArrayList.size()!=0){
        for (UnitBaseEntity u :mUnitBaseArrayList){
            daoMaster.newSession().getUnitBaseDao().insert(new UnitBase(u));
        }
    }
    request.setCacheToMemory(false);
    FLog.v(TAG,"向資料庫初始化資料成功");
    return in;
}

@Override
public Object updateAndGetAppConfig(Request request, Object in) throws Exception {
    if (request.getParam()==null){
        FLog.e(TAG,"appConfig插入時為null");
        throw new NullPointerException();
    }
    AppConfig appConfig=(AppConfig)request.getParam();
    List<DBMap> dbMapList=appConfig.transformToDBMap();
    daoMaster.newSession().getDBMapDao().insertOrReplaceInTx(dbMapList);
    FLog.v(TAG,"向資料庫更新appConfig成功");
    return appConfig;
}

@Override
public Object getAppConfig(Request request, Object in){
    AppConfig appConfig = null;
    List<DBMap> dbMapList=daoMaster.newSession().getDBMapDao().loadAll();
    if (dbMapList==null||dbMapList.size()==0)return null;
    appConfig=new AppConfig(dbMapList);
    FLog.v(TAG,"從資料庫擷取的appConfig");
    return appConfig;
}

@Override
public Object updateAndGetUserConfig(Request request, Object in) throws Exception {
    if (request.getParam()==null){
        FLog.e(TAG,"userConfig插入時為null");
        throw new NullPointerException();
    }
    UserConfig userConfig=(UserConfig) request.getParam();
    sharePreferenceDiskCache.cache((SimpleCacheKey) request.getCacheKey(),JsonUtil.objectToJson(userConfig));
    FLog.v(TAG,"向sharePreferenceDiskCache更新userConfig成功");
    return userConfig;
}

@Override
public Object getUserConfig(Request request, Object in) throws IOException {
    UserConfig userConfig= JsonUtil.jsonToObject((String) sharePreferenceDiskCache.get((SimpleCacheKey) request.getCacheKey()),UserConfig.class);
    FLog.v(TAG,"從sharePreferenceDiskCache擷取的userConfig");
    return userConfig;
}

@Override
public boolean isEnabled() {
    return enable;
}

@Override
public void setEnable(boolean enable) {
    this.enable=enable;
}
}
           
  • 3.LocalDataServiceImpl是本地存儲服務的實作類,可以看見這個類實作了Service,ToLocalDataRequest,ToNetworkRequest這三個接口,Service不必多說。可能有人要問為什麼要實作ToNetworkRequest呢?那是因為在一些向伺服器的請求之中,可能在本地中已經有緩存了,那麼此時并不需要去伺服器中取資料。我們在前面的本地儲存攔截器中也有介紹到這一點。
    • 1.可以看見這個類中有GreenDao(一種資料庫的ORM)和DiskCache<SimpleCacheKey> sharePreferenceDiskCache這兩個實作,GreenDao内部實作不是由我們實作的是以不需要抽象為接口。而sharePreferenceDiskCache是一個本地儲存抽象出來的接口和前面講的記憶體緩存接口是一個道理。我目前用的是sharePreference,當然以後有需要還可以換成用檔案系統實作,換起來也很友善。
    • 2.接下來是實作了Service的in()和out()方法,本來是需要在這兩個方法中根據請求的種類使用switch将請求分派到各個方法中的,這裡我使用了TransformDataMethodDispatch來分派,内部實作是一樣的。
    • 3.接下來的幾個方法就是對ToLocalDataRequest,ToNetworkRequest這兩個接口的實作了,這裡需要根據具體的業務邏輯進行考慮。
public class NetworkServiceImpl implements Service,ToNetworkRequest{
private boolean enable;

public NetworkServiceImpl(boolean enable) {
    this.enable = enable;
}

@Override
public Object in(Request request, Object in) throws Exception {
    return null;
}

@Override
public Object out(Request request) throws Exception {
    return TransformDataMethodDispatch.dispatch(this,null,request,null);
}

@Override
public Object patrolAccountAction_login(Request request, Object in) throws IOException {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    LoginEntity.Response response=new LoginEntity.Response(new LoginEntity.UserEntity(1,"13030512957","1",(byte) 1,"男"),"杭州",1,4,"");
    return response;
}

@Override
public Object initAppData(Request request, Object in) throws IOException {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public boolean isEnabled() {
    return enable;
}

@Override
public void setEnable(boolean enable) {
    this.enable = enable;
}
}
           
  • 4.NetworkServiceImpl就是網絡請求服務的實作了
    • 1.這裡我隻是模拟了網絡請求,大家可以使用任何網絡架構比如:Retrofit Okhttp之類的
    • 2.注意這裡的in()方法是空實作,是不會被調用到的,前面在介紹攔截器的時候已經說過了,不再贅述。
    • 3.和本地存儲服務一樣,out()方法中也使用了TransformDataMethodDispatch進行請求的分派。
以上就是Service的各個實作類,大家可能發現了,我并沒有講解類似于記憶體緩存,本地儲存以及網絡請求的具體實作,但是整個邏輯依舊是非常清晰的。是以看到這裡我想有些同學已經了解了,到底該如何設計一個架構:架構的每個層次都需要使用接口進行抽象,能使用接口進行互動的地方就别使用實作類,在改變了一個具體子功能的實作之後其他子產品并不會受到影響。 能做到前面說的幾點,我想寫出來的代碼應該算是一個比較容易擴充的架構了。

6.更加上層的封裝

我們前面将了DataEngine就算是我們的暴露給用戶端的api了,但是這個類用起來還是有點麻煩的,比如說我們的Reponse的泛型參數還沒有用起來,這樣可能在某些地方需要我們手動進行類型轉化,一不小心可能還會将類型轉錯了。是以接下來我們再在DataEngine之上封裝一層api。
public class Transform<Response1,Response2 ,Response3> implements ToLocalDataRequest<Observable<Response<Response1,Response2,Response3>>,Observable<Response>>,
    ToNetworkRequest<Observable<Response<Response1,Response2,Response3>>,Observable<Response>> {

public static <Response1> Observable<Response<Response1,Object,Object>> transformOne(Request request) {
    Transform<Response1,Object,Object> transform=new Transform<>();
    try {
        return TransformDataMethodDispatch.dispatch(transform,transform,request, DataEngine.sInstance.request(request));
    } catch (Exception e) {
        e.printStackTrace();
        return Observable.just(Response.<Response1,Object,Object>getFailedResponse(e));
    }
}

public static <Response1,Response2> Observable<Response<Response1,Response2,Object>> transformTwo(Request request) {
    Transform<Response1,Response2,Object> transform=new Transform<>();
    try {
        return TransformDataMethodDispatch.dispatch(transform,transform,request, DataEngine.sInstance.request(request));
    } catch (Exception e) {
        e.printStackTrace();
        return Observable.just(Response.<Response1,Response2,Object>getFailedResponse(e));
    }
}
public static <Response1,Response2,Response3> Observable<Response<Response1,Response2,Response3>> transformThree(Request request) {
    Transform<Response1,Response2,Response3> transform=new Transform<>();
    try {
        return TransformDataMethodDispatch.dispatch(transform,transform,request, DataEngine.sInstance.request(request));
    } catch (Exception e) {
        e.printStackTrace();
        return Observable.just(Response.<Response1,Response2,Response3>getFailedResponse(e));
    }
}


@Override
public Observable<Response<Response1, Response2, Response3>> updateAndGetAppConfig(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}

@Override
public Observable<Response<Response1, Response2, Response3>> getAppConfig(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}

@Override
public Observable<Response<Response1, Response2, Response3>> updateAndGetUserConfig(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}

@Override
public Observable<Response<Response1, Response2, Response3>> getUserConfig(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}

@Override
public Observable<Response<Response1, Response2, Response3>> patrolAccountAction_login(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}

@Override
public Observable<Response<Response1, Response2, Response3>> initAppData(Request request, Observable<Response> responseObservable) throws Exception {
    return responseObservable
            .map(new Func1<Response, Response<Response1, Response2, Response3>>() {
                @Override
                public Response<Response1, Response2, Response3> call(Response response) {
                    return response;
                }
            });
}
}
           
  • 1.這個類就是對DataEngine的封裝,這個封裝可以将DataEngine#request()中傳回的資料類,轉換成多個界面上可以直接使用的資料類。當由于不同種類的請求用到的資料類型和數量各不相同,是以這個類需要實作ToLocalDataRequest和ToNetworkRequest這兩個接口,對不同的請求傳回的結果,進行不同的轉換。
    • 1.transformOne()、transformTwo()、transformThree()這三個方法,分别表示最後轉換的結果是一個、兩個、三個。
    • 2.後面的方法都是兩個接口的實作,我舉的例子中都是不需要轉換的資料請求。

7.例子代碼

我前面已經給出了一個app登入界面的整套運作流程,項目已經測試過了問題應該不大有問題可以加我QQ,内部有資料引擎的完整代碼,項目是用MVVM+Rxjava+GreenDao寫的,大家有興趣可以去下載下傳看看,能給個star就更好了,沒興趣的同學給大家欣賞一下我們登入界面的鍊式代碼。不得不說Rxjava讓代碼邏輯變得非常清晰,而MVVM的databinding則完美的與資料引擎結合了起來。
`   isShowProgressBar.set(true);
    LocalDataEngine.getAppConfig()
            .flatMap(new Func1<AppConfig, Observable<AppConfig>>() {
                @Override
                public Observable<AppConfig> call(AppConfig appConfig) {
                    //如果為null表示第一次打開app,是以進行全局資料初始化
                    if (appConfig==null) appConfig=new AppConfig(true,"13030512957",false,false);
                    FLog.v(TAG,String.valueOf(appConfig.isFirstOpenApp()));
                    //如果不是第一次打開app,将appConfig傳入下面一個環節
                    appConfig.setAutoLogin(true);
                    appConfig.setRememberPassword(true);
                    if (appConfig.isFirstOpenApp()){
                        return LocalDataEngine.updateAndGetAppConfig(appConfig);
                    }else {
                        return Observable.just(appConfig);
                    }
                }
            }).flatMap(new Func1<AppConfig, Observable<AppConfig>>() {
                @Override
                public Observable<AppConfig> call(AppConfig appConfig) {
                    //如果是第一次打開app,那麼去伺服器拉去資料表
                    if (appConfig.isFirstOpenApp()){
                        return NetworkDataEngine.initAppData(appConfig);
                    }else {
                        //否則,将appConfig傳入下面一個環節
                        return Observable.just(appConfig);
                    }
                }
            }).filter(new Func1<AppConfig, Boolean>() {
                @Override
                public Boolean call(AppConfig appConfig) {
                    //此時如果是第一次打開app,那麼資料已經全部初始化完畢,更變第一次打開app的flag
                    //同時AppConfig已經準備好,可以進行接下來的操作了。
                    if (appConfig.isFirstOpenApp())
                        appConfig.setFirstOpenApp(false);
                    return true;
                }
            }).filter(new Func1<AppConfig, Boolean>() {
                @Override
                public Boolean call(AppConfig appConfig) {
                    //設定界面上的:記住密碼 和 自動登入 的checkBox
                    isRememberPassword.set(appConfig.isRememberPassword());
                    isAutoLogin.set(appConfig.isAutoLogin());
                    //如果全局設定中,既不需要記住密碼,也不需要自動登入,那麼就不去擷取預設的使用者資訊,直接顯示登入界面。
                    if ((!appConfig.isRememberPassword())&&(!appConfig.isAutoLogin())){
                        isShowProgressBar.set(false);
                        return false;
                    }
                    return true;
                }
            }).flatMap(new Func1<AppConfig, Observable<UserConfig>>() {
                @Override
                public Observable<UserConfig> call(AppConfig appConfig) {
                    //根據全局配置擷取預設使用者的帳号,然後去SharePreference中擷取預設使用者資料
                    return LocalDataEngine.getUserConfig(appConfig.getNowUserPhone());
                }
            }).filter(new Func1<UserConfig, Boolean>() {
                @Override
                public Boolean call(UserConfig userConfig) {
                    // 如果預設使用者資料為null,說明使用者資料緩存被清空了,或者app是第一次被打開,此時app不需要自動登入。
                    if (userConfig==null){
                        //彈出toast說明自動登入失敗的原因,并将登入界面顯示出來
                        Toast.makeText(mBaseActivity, "使用者緩存被清空,請手動登入", Toast.LENGTH_SHORT).show();
                        isShowProgressBar.set(false);
                        return false;
                    }else {
                        //資料準備就緒,進行自動登入
                        usernameObservable.set(userConfig.getRememberedPhone());
                        passwordObservable.set(userConfig.getRememberedPassword());
                        username=usernameObservable.get();
                        password=passwordObservable.get();
                        return true;
                    }
                }
            }).subscribe(new Action1<UserConfig>() {
                @Override
                public void call(UserConfig userConfig) {
                    login();
                }
            });`
           

本篇部落格隻是給大家一個啟示,告訴大家如何實作一個資料引擎的架構,内部必然會出現一些纰漏,有興趣的同學可以和我在QQ上交流。

最後大家對MVVM架構有興趣的可以看看我的這兩篇部落格

MVVM架構篇之databinding源碼解析 MVVM架構之自動增删改的極簡RecycleView的實作