最近私はグーグルによって最近導入されたアンドロイドアーキテクチャを調査しています。 ドキュメント から私はこれを見つけました:
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<Users>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// do async operation to fetch users
}
}
アクティビティは次のようにこのリストにアクセスできます。
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
model.getUsers().observe(this, users -> {
// update UI
});
}
}
私の質問は、私はこれをやるつもりです:
loadUsers()
関数で、データを非同期に取得しています。最初にデータベース(Room)でそのデータを確認します。
そこにデータが届かない場合は、Webサーバーからデータを取得するためのAPI呼び出しを行います。
取得したデータをデータベース(Room)に挿入し、そのデータに従ってUIを更新します。
これを行うための推奨される方法は何ですか?
loadUsers()
メソッドからAPIを呼び出すためにService
を起動した場合、そのService
からMutableLiveData<List<User>> users
変数を更新するにはどうすればよいですか?
私はあなたが Androidアーキテクチャコンポーネント を使っていると仮定しています。実際には、データを更新するためにservice, asynctask or handler
を呼び出している場所は関係ありません。 postValue(..)
メソッドを使用して、サービスまたはasynctaskからデータを挿入できます。あなたのクラスはこのようになります:
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
users
はLiveData
であるため、Room
データベースは、挿入された場所にかかわらず、ユーザーデータを提供します。
Note:
MVVMのようなアーキテクチャでは、リポジトリは主にローカルデータとリモートデータのチェックと取得を担当します。
バックグラウンドスレッドからライブデータのpostValue(..)メソッドを使用してください。
private void loadUsers() {
// do async operation to fetch users and use postValue() method
users.postValue(listOfData)
}
... loadUsers()関数で非同期にデータを取得しています... loadUsers()メソッドからAPIを呼び出すためにサービスを開始した場合、そのサービスからMutableLiveData> users変数を更新する方法
アプリがバックグラウンドスレッドでユーザーデータを取得している場合は、 setValue ではなく postValue が便利です。
LoadDataメソッドには、MutableLiveDataの "users"オブジェクトへの参照があります。 loadDataメソッドはまた、どこか(リポジトリなど)から新しいユーザーデータを取得します。
実行がバックグラウンドスレッドで行われる場合、MutableLiveData.postValue()はMutableLiveDataオブジェクトの外部オブザーバを更新します。
多分このようなもの:
private MutableLiveData<List<User>> users;
.
.
.
private void loadUsers() {
// do async operation to fetch users
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(new Runnable() {
@Override
public void run() {
// on background thread, obtain a fresh list of users
List<String> freshUserList = aRepositorySomewhere.getUsers();
// now that you have the fresh user data in freshUserList,
// make it available to outside observers of the "users"
// MutableLiveData object
users.postValue(freshUserList);
}
});
}
LiveData
やViewModel
などの新しいアーキテクチャーモジュールに付随する Androidアーキテクチャーガイド を見てください。彼らはこの正確な問題について深く議論しています。
彼らの例では、彼らはそれをサービスに入れません。彼らが「リポジトリ」モジュールとRetrofitを使ってどのようにそれを解決するかを見てください。下部の補遺には、ネットワーク状態の伝達、エラーの報告など、より完全な例が含まれています。
https://developer.Android.com/topic/libraries/architecture/guide.html
あなたの問題に対して非常に良い答えを持っています。一番下までスクロールして、データベースにレスポンスを保存し、LiveDataを使用してUIを更新する方法を確認します。
あなたがリポジトリであなたのAPIを呼んでいるならば、
In リポジトリ:
public MutableLiveData<LoginResponseModel> checkLogin(LoginRequestModel loginRequestModel) {
final MutableLiveData<LoginResponseModel> data = new MutableLiveData<>();
apiService.checkLogin(loginRequestModel)
.enqueue(new Callback<LoginResponseModel>() {
@Override
public void onResponse(@NonNull Call<LoginResponseModel> call, @Nullable Response<LoginResponseModel> response) {
if (response != null && response.isSuccessful()) {
data.postValue(response.body());
Log.i("Response ", response.body().getMessage());
}
}
@Override
public void onFailure(@NonNull Call<LoginResponseModel> call, Throwable t) {
data.postValue(null);
}
});
return data;
}
In ViewModel
public LiveData<LoginResponseModel> getUser() {
loginResponseModelMutableLiveData = repository.checkLogin(loginRequestModel);
return loginResponseModelMutableLiveData;
}
In Activity/Fragment
loginViewModel.getUser().observe(LoginActivity.this, loginResponseModel -> {
if (loginResponseModel != null) {
Toast.makeText(LoginActivity.this, loginResponseModel.getUser().getType(), Toast.LENGTH_SHORT).show();
}
});
注:ここではJava_1.8ラムダを使用していますが、それなしでも使用できます