How should I get Resources(R.string) in viewModel in Android (MVVM and databinding)
Solution 1:
You can access the context by implementing AndroidViewModel instead of ViewModel.
class MainViewModel(application: Application) : AndroidViewModel(application) {
fun getSomeString(): String? {
return getApplication<Application>().resources.getString(R.string.some_string)
}
}
Solution 2:
You can also use the Resource Id and ObservableInt to make this work.
ViewModel:
val contentString = ObservableInt()
contentString.set(R.string.YOUR_STRING)
And then your view can get the text like this:
android:text="@{viewModel.contentString}"
This way you can keep the context out of your ViewModel
Solution 3:
Just create a ResourceProvider class that fetch resources using Application context. In your ViewModelFactory instantiate the resource provider using App context. You're Viewmodel is Context free and can be easily testable by mocking the ResourceProvider.
Application
public class App extends Application {
private static Application sApplication;
@Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
public static Application getApplication() {
return sApplication;
}
ResourcesProvider
public class ResourcesProvider {
private Context mContext;
public ResourcesProvider(Context context){
mContext = context;
}
public String getString(){
return mContext.getString(R.string.some_string);
}
ViewModel
public class MyViewModel extends ViewModel {
private ResourcesProvider mResourcesProvider;
public MyViewModel(ResourcesProvider resourcesProvider){
mResourcesProvider = resourcesProvider;
}
public String doSomething (){
return mResourcesProvider.getString();
}
ViewModelFactory
public class ViewModelFactory implements ViewModelProvider.Factory {
private static ViewModelFactory sFactory;
private ViewModelFactory() {
}
public static ViewModelFactory getInstance() {
if (sFactory == null) {
synchronized (ViewModelFactory.class) {
if (sFactory == null) {
sFactory = new ViewModelFactory();
}
}
}
return sFactory;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(MainActivityViewModel.class)) {
return (T) new MainActivityViewModel(
new ResourcesProvider(App.getApplication())
);
}
throw new IllegalArgumentException("Unknown ViewModel class");
}
}