0

Room Db 및 Retrofit에 대한 NetworkBoundResourceResource 도우미 클래스를 구현할 때 완벽하게 작동합니다. 그러나 검색 결과를 RESTful에서 방을 사용하여 개조해야합니다. 방을 사용해야합니다. Resources 클래스는 좋으며 변경하지 않아도됩니다. 내가 뭘 원하는이 클래스 안에 DB 소스를 제거하려고합니다.방이없는 NetworkBoundResource 도우미 클래스

public abstract class NetworkBoundResource<ResultType, RequestType> { 
    private final AppExecutors appExecutors; 

    private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>(); 

    @MainThread 
    public NetworkBoundResource(AppExecutors appExecutors) { 
    this.appExecutors = appExecutors; 
    result.setValue(Resource.loading(null)); 
    LiveData<ResultType> dbSource = loadFromDb(); 
    result.addSource(dbSource, data -> { 
     result.removeSource(dbSource); 
     if (shouldFetch(data)) { 
     fetchFromNetwork(dbSource); 
     } else { 
     result.addSource(dbSource, newData -> setValue(Resource.success(newData))); 
     } 
    }); 
    } 

    @MainThread 
    private void setValue(Resource<ResultType> newValue) { 
    if (!Objects.equals(result.getValue(), newValue)) { 
     result.setValue(newValue); 
    } 
    } 

    private void fetchFromNetwork(final LiveData<ResultType> dbSource) { 
    LiveData<ApiResponse<RequestType>> apiResponse = createCall(); 
    // we re-attach dbSource as a new source, it will dispatch its latest value quickly 
    result.addSource(dbSource, newData -> setValue(Resource.loading(newData))); 
    result.addSource(apiResponse, response -> { 
     result.removeSource(apiResponse); 
     result.removeSource(dbSource); 
     //noinspection ConstantConditions 
     if (response.isSuccessful()) { 
     appExecutors.diskIO().execute(() -> { 
      saveCallResult(processResponse(response)); 
      appExecutors.mainThread().execute(() -> 
       // we specially request a new live data, 
       // otherwise we will get immediately last cached value, 
       // which may not be updated with latest results received from network. 
       result.addSource(loadFromDb(), 
        newData -> setValue(Resource.success(newData))) 
     ); 
     }); 
     } else { 
     onFetchFailed(); 
     result.addSource(dbSource, 
      newData -> setValue(Resource.error(response.errorMessage, newData))); 
     } 
    }); 
    } 

    protected void onFetchFailed() { 
    } 

    public LiveData<Resource<ResultType>> asLiveData() { 
    return result; 
    } 

    @WorkerThread 
    protected RequestType processResponse(ApiResponse<RequestType> response) { 
    return response.body; 
    } 

    @WorkerThread 
    protected abstract void saveCallResult(@NonNull RequestType item); 

    @MainThread 
    protected abstract boolean shouldFetch(@Nullable ResultType data); 

    @NonNull 
    @MainThread 
    protected abstract LiveData<ResultType> loadFromDb(); 

    @NonNull 
    @MainThread 
    protected abstract LiveData<ApiResponse<RequestType>> createCall(); 
} 
+0

'NetworkBoundResource'를 그대로 두려고했는데 두 개의 보호 된 메소드'saveCallResult()'와'loadFromDb()'에서 비헤이비어를 토글하고'shouldFetch()'가 항상 true를 반환하도록 할 수 있습니까? – amrro

답변

1

문제는 NetworkBoundResource이처럼로드 된 데이터가 다음 UI로 데이터베이스에서로드, 먼저 데이터베이스를 통과해야한다는 것입니다. 결과적으로, 내가 한 것은 영구 데이터베이스를 분리하고로드 할 임시 필드를 생성하는 것입니다. 나는 original 검색 방법을 편집하고 싶었 예를 들어

, 내가 제안 :

public LiveData<Resource<List<Repo>>> search(String query) { 
    return new NetworkBoundResource<List<Repo>, RepoSearchResponse>(appExecutors) { 

     // Temp ResultType 
     private List<Repo> resultsDb; 

     @Override 
     protected void saveCallResult(@NonNull RepoSearchResponse item) { 
      // if you don't care about order 
      resultsDb = item.getItems(); 
     } 

     @Override 
     protected boolean shouldFetch(@Nullable List<Repo> data) { 
      // always fetch. 
      return true; 
     } 

     @NonNull 
     @Override 
     protected LiveData<List<Repo>> loadFromDb() { 
      if (resultsDb == null) { 
       return AbsentLiveData.create(); 
      }else { 
       return new LiveData<List<Repo>>() { 
        @Override 
        protected void onActive() { 
         super.onActive(); 
         setValue(resultsDb); 
        } 
       }; 
      } 
     } 

     @NonNull 
     @Override 
     protected LiveData<ApiResponse<RepoSearchResponse>> createCall() { 
      return githubService.searchRepos(query); 
     } 

     @Override 
     protected RepoSearchResponse processResponse(ApiResponse<RepoSearchResponse> response) { 
      RepoSearchResponse body = response.body; 
      if (body != null) { 
       body.setNextPage(response.getNextPage()); 
      } 
      return body; 
     } 
    }.asLiveData(); 
} 

나는 그것을 실행하고 그것을 작동합니다.

+1

그건 나를 위해 작동하지 않습니다. processResponse- 블록을 작성하는 방법을 제게 설명해 주시겠습니까? – romaneso