我采用了 Google 在他们的示例中使用的存储库模式,它为您提供了单一的事实来源(您的 Room 数据库)。
这里讨论:https ://developer.android.com/jetpack/docs/guide
需要注意的关键部分是 NetworkBoundResource 类(Google 示例:https ://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example /github/repository/NetworkBoundResource.kt)。这个来自 Google 的示例在 Kotlin 中,我确实找到了一个 Java 示例。
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package iammert.com.androidarchitecture.data;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MediatorLiveData;
import android.os.AsyncTask;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public abstract class NetworkBoundResource<ResultType, RequestType> {
private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>();
@MainThread
NetworkBoundResource() {
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 -> result.setValue(Resource.success(newData)));
}
});
}
private void fetchFromNetwork(final LiveData<ResultType> dbSource) {
result.addSource(dbSource, newData -> result.setValue(Resource.loading(newData)));
createCall().enqueue(new Callback<RequestType>() {
@Override
public void onResponse(Call<RequestType> call, Response<RequestType> response) {
result.removeSource(dbSource);
saveResultAndReInit(response.body());
}
@Override
public void onFailure(Call<RequestType> call, Throwable t) {
onFetchFailed();
result.removeSource(dbSource);
result.addSource(dbSource, newData -> result.setValue(Resource.error(t.getMessage(), newData)));
}
});
}
@MainThread
private void saveResultAndReInit(RequestType response) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
saveCallResult(response);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
result.addSource(loadFromDb(), newData -> result.setValue(Resource.success(newData)));
}
}.execute();
}
@WorkerThread
protected abstract void saveCallResult(@NonNull RequestType item);
@MainThread
protected boolean shouldFetch(@Nullable ResultType data) {
return true;
}
@NonNull
@MainThread
protected abstract LiveData<ResultType> loadFromDb();
@NonNull
@MainThread
protected abstract Call<RequestType> createCall();
@MainThread
protected void onFetchFailed() {
}
public final LiveData<Resource<ResultType>> getAsLiveData() {
return result;
}
}
这是使用该类的回购:
package iammert.com.androidarchitecture.data;
import android.arch.lifecycle.LiveData;
import android.support.annotation.NonNull;
import java.util.List;
import javax.inject.Inject;
import iammert.com.androidarchitecture.data.local.dao.MovieDao;
import iammert.com.androidarchitecture.data.local.entity.MovieEntity;
import iammert.com.androidarchitecture.data.remote.MovieDBService;
import iammert.com.androidarchitecture.data.remote.model.MoviesResponse;
import retrofit2.Call;
/**
* Created by mertsimsek on 19/05/2017.
*/
public class MovieRepository {
private final MovieDao movieDao;
private final MovieDBService movieDBService;
@Inject
public MovieRepository(MovieDao movieDao, MovieDBService movieDBService) {
this.movieDao = movieDao;
this.movieDBService = movieDBService;
}
public LiveData<Resource<List<MovieEntity>>> loadPopularMovies() {
return new NetworkBoundResource<List<MovieEntity>, MoviesResponse>() {
@Override
protected void saveCallResult(@NonNull MoviesResponse item) {
movieDao.saveMovies(item.getResults());
}
@NonNull
@Override
protected LiveData<List<MovieEntity>> loadFromDb() {
return movieDao.loadMovies();
}
@NonNull
@Override
protected Call<MoviesResponse> createCall() {
return movieDBService.loadMovies();
}
}.getAsLiveData();
}
public LiveData<MovieEntity> getMovie(int id){
return movieDao.getMovie(id);
}
}
我将尝试简要解释一下,您的存储库中有一个方法,例如 loadMovies(),它从存储库中返回电影的 LiveData 列表。使用 NetworkBoundResource,首先检查 Room 数据库,然后查询 API,然后将结果加载到数据库中。更新数据库后,您正在观察的 LiveData 将使用新结果进行更新。
此图显示了其背后的逻辑流程:
正如您在上面看到的,您正在观察磁盘的变化,并在它发生变化时收到更新。
我建议阅读我之前链接的那个 Jetpack 指南,因为他们会更详细地解释它。我相信这就是你要找的。