在 Activity 或 Fragment 之外获取 ViewModel 实例的正确方法
The correct way to obtain a ViewModel instance outside of an Activity or a Fragment
我正在构建一个定位应用程序,在其中显示来自我的 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)
}
}
}
}
}
问题是我应该如何在非 activity class 中获取 LocationViewModel 实例,例如 BroadcastReceiver?调用 locationViewModel = ViewModelProviders.of(context).get(LocationViewModel.class)
是否正确,其中上下文是我从 BroadcastReceiver 的 onReceive (Context context, Intent intent)
接收到的上下文?
获得 ViewModel 后,是否需要使用 LiveData.observeForever and LiveData.removeObserver 因为 BroadcastReceiver 不是 LifecycleOwner?
传递 ViewModel 实例是一种反模式。
理想情况下,ViewModel 使用输入流(允许通过 BroasdcastReceiver 进行位置更新、用户操作等更新)和输出流(供 Activity/ 片段观察和显示到用户)
你的大致依赖创建应该是这样的,如果可以请使用像Dagger这样的DI框架:
主要Activity
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 的 Subject 非常相似,非常适合这里的输入流。
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);
}
}
}
现在你可以只观察输出流,它可以是一个 LiveData 流,而不是 RxJava 的 Observable。
这种方式数据真正以一种方式流动,符合 MVVM 架构
Question is how should I get the LocationViewModel instance in a
non-activity class like this BroadcastReceiver?
你不应该那样做。这是糟糕的设计实践。
Is it correct to call locationViewModel =
ViewModelProviders.of(context).get(LocationViewModel.class) where
context is the context that I receive from onReceive (Context context,
Intent intent) of the BroadcastReceiver?
没有。没用
您可以通过以下方式实现您想要的结果:
在单独的单例 class 中将您的 Room DB 操作与 ViewModel
分开。在 ViewModel
和任何其他需要的地方使用它。当接收到 Broadcast 时,通过这个单例 class 而不是 ViewModel
将数据写入 DB。
如果您正在观察片段中的 LiveData
,那么它也会更新您的视图。
我正在构建一个定位应用程序,在其中显示来自我的 MainActivity 中的 Room 数据库的背景位置。我可以通过调用
来获取 ViewModellocationViewModel = 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)
}
}
}
}
}
问题是我应该如何在非 activity class 中获取 LocationViewModel 实例,例如 BroadcastReceiver?调用 locationViewModel = ViewModelProviders.of(context).get(LocationViewModel.class)
是否正确,其中上下文是我从 BroadcastReceiver 的 onReceive (Context context, Intent intent)
接收到的上下文?
获得 ViewModel 后,是否需要使用 LiveData.observeForever and LiveData.removeObserver 因为 BroadcastReceiver 不是 LifecycleOwner?
传递 ViewModel 实例是一种反模式。
理想情况下,ViewModel 使用输入流(允许通过 BroasdcastReceiver 进行位置更新、用户操作等更新)和输出流(供 Activity/ 片段观察和显示到用户)
你的大致依赖创建应该是这样的,如果可以请使用像Dagger这样的DI框架:
主要Activity
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 的 Subject 非常相似,非常适合这里的输入流。
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);
}
}
}
现在你可以只观察输出流,它可以是一个 LiveData 流,而不是 RxJava 的 Observable。
这种方式数据真正以一种方式流动,符合 MVVM 架构
Question is how should I get the LocationViewModel instance in a non-activity class like this BroadcastReceiver?
你不应该那样做。这是糟糕的设计实践。
Is it correct to call locationViewModel = ViewModelProviders.of(context).get(LocationViewModel.class) where context is the context that I receive from onReceive (Context context, Intent intent) of the BroadcastReceiver?
没有。没用
您可以通过以下方式实现您想要的结果:
在单独的单例 class 中将您的 Room DB 操作与 ViewModel
分开。在 ViewModel
和任何其他需要的地方使用它。当接收到 Broadcast 时,通过这个单例 class 而不是 ViewModel
将数据写入 DB。
如果您正在观察片段中的 LiveData
,那么它也会更新您的视图。