web-dev-qa-db-ja.com

バックグラウンドサービスとUpdate UIからViewModelのLiveDataを更新する方法

最近私はグーグルによって最近導入されたアンドロイドアーキテクチャを調査しています。 ドキュメント から私はこれを見つけました:

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
        });
    }
}

私の質問は、私はこれをやるつもりです:

  1. loadUsers()関数で、データを非同期に取得しています。最初にデータベース(Room)でそのデータを確認します。

  2. そこにデータが届かない場合は、Webサーバーからデータを取得するためのAPI呼び出しを行います。

  3. 取得したデータをデータベース(Room)に挿入し、そのデータに従ってUIを更新します。

これを行うための推奨される方法は何ですか?

loadUsers()メソッドからAPIを呼び出すためにServiceを起動した場合、そのServiceからMutableLiveData<List<User>> users変数を更新するにはどうすればよいですか?

63
CodeCameo

私はあなたが Androidアーキテクチャコンポーネント を使っていると仮定しています。実際には、データを更新するためにservice, asynctask or handlerを呼び出している場所は関係ありません。 postValue(..)メソッドを使用して、サービスまたはasynctaskからデータを挿入できます。あなたのクラスはこのようになります:

private void loadUsers() {
    // do async operation to fetch users and use postValue() method
    users.postValue(listOfData)
}

usersLiveDataであるため、Roomデータベースは、挿入された場所にかかわらず、ユーザーデータを提供します。

Note: MVVMのようなアーキテクチャでは、リポジトリは主にローカルデータとリモートデータのチェックと取得を担当します。

59

バックグラウンドスレッドからライブデータのpostValue(..)メソッドを使用してください。

private void loadUsers() {
    // do async operation to fetch users and use postValue() method
   users.postValue(listOfData)
}
41
minhazur

... 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);        
        }
    });

}
15
albert c braun

LiveDataViewModelなどの新しいアーキテクチャーモジュールに付随する Androidアーキテクチャーガイド を見てください。彼らはこの正確な問題について深く議論しています。

彼らの例では、彼らはそれをサービスに入れません。彼らが「リポジトリ」モジュールとRetrofitを使ってどのようにそれを解決するかを見てください。下部の補遺には、ネットワーク状態の伝達、エラーの報告など、より完全な例が含まれています。

4
user1978019

https://developer.Android.com/topic/libraries/architecture/guide.html

あなたの問題に対して非常に良い答えを持っています。一番下までスクロールして、データベースにレスポンスを保存し、LiveDataを使用してUIを更新する方法を確認します。

enter image description here

2
Prakash

あなたがリポジトリであなたの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ラムダを使用していますが、それなしでも使用できます

1
Shubham Agrawal