我已经开始为Android应用程序开发MVVM架构。我怀疑是否将上下文传递给视图模型是正确的?如果没有,那么我的视图模型如何在需要时可以访问上下文。
我正在做以下事情:
由于共享首选项需要上下文来实例化对象。
我是这个架构的新手,任何指导对我都有帮助,提前谢谢。
答案 0 :(得分:6)
我认为ApplicationContext
的使用是可以的,您可以从AndroidViewModel
扩展ViewModel,并且只要需要引用上下文,就可以使用getApplication()
方法。
更好的是,如果你使用匕首,你根本不需要这个,你只需要在你需要的地方注入你的ApplicationContext。它可以在您的视图模型或处理共享首选项等的实用程序类中。
答案 1 :(得分:4)
这是Android社区长期争论不休的讨论。当我们提到MVC时,很明显模型(也就是数据保持对象)是M,Controllers = C用于Activity类(在iOS中它们实际上称为UIViewControllers),而用于Android中View的V是XML文件本身。现在有些人会争论代表什么的建筑细分。但是,让我们超越这个并讨论MVVM。
MVVM已经存在很多年了。过去曾经有过一些尝试通过第三方绑定工具将它带到Android,但它最终会变得更加hacky然后值得。最近随着原生数据绑定的发布,Android终于能够做一些有点干净的MVVM实现。所以这里有几个选项。你可以做到
M =模型(数据保持对象)
V = Views(表示UI的XML文件本身)
VM =这是争论的地方。
有人说为了成为一个“真正的”ViewModel,必须与Presentation层真正分离,而Activity类本身具有生命周期回调,因此不值得被称为ViewModel。
其他(自包含)会指出,为了处理从ViewModel触发的大多数操作,必须具有onActivityResult,onNewIntent,onBroadcastReceived,onPause或其他生命周期处理的意识,以适当地管理用户体验。所以在我的团队中,我们将Activity视为ViewModel。否则,你将活动传递给一个视图模型并将两者紧密耦合在一起,造成巨大的可怕维护代码噩梦。
所以,如果您想要我的意见,请坚持将Activity视为您的ViewModel。像在WPF中的任何其他绑定技术(如INotifyPropertyChanged)一样,将数据提供给ViewModel。你可以通过Binding来实现。
我做了两件事来实现这一目标。我在XML布局中有一个Activity变量,用于在onCreate中注入绑定设置,该设置为viewModel中的任何可观察属性(即活动)提供XML直接绑定权限。然后我注入了我需要使用的任何变量,例如,你可能有一个WeatherModel填充一个预测,该预测存在于你也将在onCreate中设置的Activity中,以允许XML访问它的ViewModel(aka activity)它是viewModel的对象。
另一种方法是制作一个ViewModel对象并将其注入活动的onCreate中的XML中,然后继续从活动中来回调用viewmodel以处理操作和生命周期,并随意管理那个噩梦哈哈,我用这种方式完成了一个完整的项目,到最后,我重新编写了一切,以避免编码工作的重复和可怕的来回重复。
Goodluck,我希望有所帮助。
答案 2 :(得分:2)
一个非常好的问题,它并不像看起来那么简单! You can see an example from Google team here
他们在工厂的帮助下解决了这个问题。 它传递(当然)应用程序上下文(不是活动上下文!)。
一个小问题 - 以及如此多的样板代码!
我的决定:
public class MainApplication extends Application {
public void onCreate() {
AppSharedPref sharedPref = AppSharedPref.getInstance(PreferenceManager.getDefaultSharedPreferences(this));
AppRepository.getInstance(sharedPref);
存储库是单一的(为简洁起见,会跳过很多代码):
public class AppRepository implements AppDataSource {
public static AppRepository getInstance(@NonNull AppSharedPref sharedPref) {
if (INSTANCE == null) {
INSTANCE = new AppRepository(sharedPref);
}
return INSTANCE;
}
在ViewModel调用中:
public class MyViewModel extends AndroidViewModel {
// constructor
public MyViewModel(@NonNull Application application) {
repository = AppRepository.getInstance(.....);
}
答案 3 :(得分:0)
在这种情况下,您应该使用AndroidViewModel
类或在您的ViewModel
实现中继续引用Application上下文。
ViewModel
类旨在通过其生命周期在Activity
的不同实例之间保持数据持久,并且存储对Activity
实例上下文之一的引用确实没有用。
答案 4 :(得分:0)
查看Dagger 2!
是的,您绝对不应该将git fetch origin master
git rebase origin/master
git push origin master
传递给Activity
或xml
。这将使您的ViewModel
不会比我们试图从此体系结构转移的2000行活动更好。
MVVM项目中的解决方案是用ViewModel
注入SharedPreferences
。您也可以使用Dagger
,但是在项目中是否需要ApplicationContext
的多个实例?
我们有一个SharedPreferences
的实用程序类,很高兴让它保持单例并在需要的地方注入。
答案 5 :(得分:0)
我在应用程序中使用了MVVM。我总是尽量不要在视图模型中使用上下文。我还遇到了SharedPreferences的问题,它需要上下文来访问首选项文件。我不使用Dagger的解决方案之一是创建一个Preference实用程序类,该类将引用应用程序上下文。您可以在Application类中初始化此实用工具类。您可以通过实用程序类提供的公共静态方法来引用共享首选项。您可以从存储库类中直接调用实用程序类。我更喜欢在存储库类中包含与数据存储有关的所有逻辑,这就是为什么我在存储库类中调用sharedpreference实用程序类。
PreferenceManager.java
public class PreferenceManager {
private static SharedPreferences mSharedpreferences;
private PreferenceManager() {}
public static void initialize(Context context) {
mSharedpreferences= context.getSharedPreferences(context.getPackageName(),
Context.MODE_PRIVATE);
}
public static SharedPreferences getSharedPreferences() {
return mSharedpreferences;
}
}
App.java
public class App extends Application {
@Override
public void onCreate() {
PreferenceManager.initialize(this);
}
}
Repository.java
public class Repository {
public void someMethod() {
PreferenceManager.getSharedPreferences.edit.putBoolean("sample", true).apply();
}