Ish*_*arg 5 android-mvvm android-room android-livedata android-architecture-components
我浏览了许多可用于新架构组件的示例代码,但是在设置项目时仍然遇到一些问题。
我需要从远程服务中获取数据并将其保存到会议室数据库中。我希望我的视图仅观察一个实时数据列表。我的AppRepository处理RemoteRepository和LocalRepository。远程存储库具有fetchMovies()方法,该方法从Web服务接收电影列表。我想将此列表保存在会议室数据库中,目前我的RemoteRepository类正在执行此操作。
public void fetchMovieFromRemote(int page){
movieService.fetchPopularMovies(ApiConstants.BASE_URL, page).enqueue(new Callback<List<Movie>>() {
@Override
public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {
int statusCode = response.code();
if (statusCode == 200){
mLocalRepository.insert(response.body());
}
}
@Override
public void onFailure(Call<List<Movie>> call, Throwable t) {
}
});
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,理想情况下,远程存储库和本地存储库应独立,并且此工作应由AppRepository类完成。一种方法是使用回调,但我想使用实时数据来实现。fetchMovieFromRemote(int page)方法是否应该为此返回一个实时数据,但是在那种情况下,如何在我的viewmodel中处理它,该模型目前具有房间返回的电影列表的实时数据。
@Query("SELECT * from movie ORDER BY id ASC")
LiveData<List<Movie>> getAllWords();
Run Code Online (Sandbox Code Playgroud)
我是MVVM的新手,请引导我了解此架构的理想方法。
我采用了 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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是使用该类的回购:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
我将尝试简要解释一下,您的 Repo 中有一个方法,例如 loadMovies(),它从您的存储库中返回电影的 LiveData 列表。使用 NetworkBoundResource,首先检查 Room 数据库,然后查询 API,然后将结果加载到数据库中。数据库更新后,您正在观察的 LiveData 将使用新结果进行更新。
此图显示了这背后的逻辑流程:
正如您在上面看到的,您正在观察磁盘的变化,并在它发生变化时收到更新。
我建议通读我之前链接的那个 Jetpack 指南,因为他们会更详细地解释它。我相信这就是你要找的。
| 归档时间: |
|
| 查看次数: |
1401 次 |
| 最近记录: |