MainActivityのRoomデータベースから背景の場所を表示する場所アプリを構築しています。呼び出すことでViewModelを取得できます
_locationViewModel = ViewModelProviders.of(this).get(LocationViewModel.class);
locationViewModel.getLocations().observe(this, this);
_
BroadCastReceiverを介して位置情報の更新を受信したときに、定期的な背景の位置をRoomデータベースに保存する必要があります。 locationViewModel.getLocations().setValue()
を呼び出して保存する必要があります
_public class LocationUpdatesBroadcastReceiver extends BroadcastReceiver {
static final String ACTION_PROCESS_UPDATES =
"com.google.Android.gms.location.sample.backgroundlocationupdates.action" +
".PROCESS_UPDATES";
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS_UPDATES.equals(action)) {
LocationResult result = LocationResult.extractResult(intent);
if (result != null) {
List<Location> locations = result.getLocations();
List<SavedLocation> locationsToSave = covertToSavedLocations(locations)
//Need an instance of LocationViewModel to call locationViewModel.getLocations().setValue(locationsToSave)
}
}
}
}
}
_
このBroadcastReceiverのような非アクティビティクラスでLocationViewModelインスタンスを取得するにはどうすればよいですか。 BroadcastReceiverのlocationViewModel = ViewModelProviders.of(context).get(LocationViewModel.class)
から受け取ったコンテキストであるonReceive (Context context, Intent intent)
を呼び出すことは正しいですか?
ViewModelを取得した後、BroadcastReceiverはLifecycleOwnerではないため、 LiveData.observeForever および LiveData.removeObserver を使用する必要がありますか?
このBroadcastReceiverのような非アクティビティクラスでLocationViewModelインスタンスを取得するにはどうすればよいですか。
あなたはそれをするべきではありません。その悪い設計慣行。
LocationViewModel = ViewModelProviders.of(context).get(LocationViewModel.class)を呼び出すのは正しいですか。ここで、contextはBroadcastReceiverのonReceive(Context context、Intent intent)から受け取るコンテキストです。
いいえ、役に立たない
次のようにして、希望する結果を得ることができます:
別のシングルトンクラスで、Room DB操作をViewModel
から分離します。 ViewModel
およびその他の必要な場所で使用します。ブロードキャストを受信したら、ViewModel
ではなく、このシングルトンクラスを介してデータをDBに書き込みます。
フラグメントのLiveData
を監視している場合は、ビューも更新されます。
これは、ViewModelインスタンスを渡すアンチパターンです。
理想的には、ViewModelは入力ストリーム(BroasdcastReceiverを介した位置の更新、ユーザーのアクションなどの更新を可能にする)と出力ストリーム(Activity/Fragmentがユーザーに観察および表示するため)で一度設定されます。
大まかな依存関係の作成は次のようにする必要があります。できればDaggerのようなDIフレームワークを使用してください。
MainActivity
protected void onCreate(Bundle savedBundleState) {
PublishSubject<List<SavedLocation>> currentLocationSubject = new PublishSubject();// here I'm using RxJava but you can use alternatives
MyBroastcastReceiver broadcastReceiver = new MyBroadcastReceiver(currentLocationSubject);
locationViewModel = ViewModelProviders.of(this).get(LocationViewModel.class);
locationViewModel.setLocationInputStream(currentLocationSubject);
locationViewModel.init();
}
MutableLiveDataは、ここでの入力ストリームに最適なRxJavaのサブジェクトに非常に似ています。
MyBroastcastReceiver
static final String ACTION_PROCESS_UPDATES =
"com.google.Android.gms.location.sample.backgroundlocationupdates.action" +
".PROCESS_UPDATES";
private PublishSubject<List<SavedLocation>> currentLocationSubject = new PublishSubject();
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS_UPDATES.equals(action)) {
LocationResult result = LocationResult.extractResult(intent);
if (result != null) {
List<Location> locations = result.getLocations();
List<SavedLocation> locationsToSave = covertToSavedLocations(locations)
currentLocationSubject.onNext(locationsToSave);// add input to the input stream
}
}
}
}
LocationViewModel
Observable<List<SavedLocation>> inputLocationStream;
PublishSubject<List<SavedLocation>> outputLocationStream = new PublishSubject();
void setLocationInputStream(Observable<List<SavedLocation>> inputLocationStream) {
this.inputLocationStream = inputLocationStream;
}
void init() {
inputLocationStream.subscribe {
saveLocationList -> {
outputLocationStream.onNext(saveLocationList);
}
}
}
これで、RxJavaのObservableの代わりにLiveDataストリームにすることができる出力ストリームを観察できます。
この方法でデータは実際に一方向に流れ、MVVMアーキテクチャーに準拠