Reputation: 2731
I have a String inside my Fragment that I'm trying to inject into the Fragment's ViewModel.
I've been following this tutorial https://github.com/google/dagger/issues/2287
but I can't get the correct syntax from kotlin to java to work.
@AssistedFactory
public interface MainViewModelFactory {
MainViewModel create(String s);
}
@HiltViewModel
public class MainViewModel extends ViewModel {
private static final String TAG = "MainViewModel";
@Inject
public MainViewModel(@Assisted String testString) {
Log.d(TAG, "MainViewModel: Success injecting: " + testString);
}
@SuppressWarnings("unchecked")
public static ViewModelProvider.Factory provideFactory(
MainViewModelFactory assistedFactory,
String s
){
return new ViewModelProvider.Factory() {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) assistedFactory.create(s);
}
};
}
}
@Inject
MainViewModelFactory viewModelFactory;
private MainViewModel mainViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mainViewModel = new ViewModelProvider(this).get(MainViewModel.provideFactory(viewModelFactory, "Test string"));
//This line fails to even compile because I can't figure out how to fix my syntax from the kotlin to java conversion.
}
How can I correctly provide the ViewModel
from my factory method?
When I try to compile it I get
An assisted factory's abstract method must return a type with an @AssistedInject-annotated constructor.
on my factory class's method create
.
Edit:
I know you can use a module to provide the string, but I'm using it as a simple example before I try to get it working with injecting an object.
Using Hilt 2.37:
implementation 'com.google.dagger:hilt-android:2.37'
annotationProcessor 'com.google.dagger:hilt-compiler:2.37'
Upvotes: 2
Views: 1758
Reputation: 2731
Took two days to figure it out...but here's how to runtime inject (assisted injection) with hilt using Java.
Requirements: Dagger 2.31+
Important notes:
DO NOT annotate your ViewModel with @HiltViewModel
or it will throw a compile time exception which did not help me identify the issue at all.
ViewModel constructor should be annotated with @Inject instead of @AssistedInject.
[Hilt] Processing did not complete. See error above for details.
Full code with String
example:
@AssistedFactory
public interface MainViewModelFactory {
MainViewModel create(String s);
}
public class MainViewModel extends ViewModel {
private static final String TAG = "MainViewModel";
@AssistedInject
public MainViewModel(@Assisted String testString) {
Log.d(TAG, "MainViewModel: Success injecting: " + testString);
}
@SuppressWarnings("unchecked")
public static ViewModelProvider.Factory provideFactory(
MainViewModelFactory assistedFactory,
String s
){
return new ViewModelProvider.Factory() {
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) assistedFactory.create(s);
}
};
}
}
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity {
@Inject
MainViewModelFactory viewModelFactory;
private MainViewModel mainViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mainViewModel = new ViewModelProvider(
this,
MainViewModel.provideFactory(viewModelFactory, "Test string")
).get(MainViewModel.class);
}
Took me a while to figure out there was a second param for ViewModelProvider
which needed the injected ViewModelFactory
to create the ViewModelProvider
Hopefully this answer helps people in the future. I couldn't find any examples of how to do it.
Helpful answers:
https://github.com/google/dagger/issues/2287#issuecomment-761811164
Converting the kotlin way of creating the Java equivalent of ViewModelProviders
was quite confusing...
Upvotes: 3
Reputation: 617
First, You must add @Inject Annotation On Constructor Of Your Class
Second, if your Constructor of your class has an argument or Object that is hard to Instantiate for dagger, You have to provide it from Module Class.
for Example if your class use String Class or use an interface, abstract class that cannot be instantiate, you must provide an instance of that class in your Module Class.
In your ViewModel Class you can get it like repository class, because repository class is a simple class, dagger knows how to instantiate it, so there is no problem.
public class FragmentViewModel extends ViewModel {
private final RemoteRepository remoteRepository;
private final TestClass testClass;
@Inject
public CardInfoViewModel(RemoteRepository remoteRepository, TestClass testClass) { //How to inject object from Fragment into constructor?
this.remoteRepository = remoteRepository;
this.testClass = testClass;
}
}
module class
@InstallIn(Singletone.class)
@Module
public class ModuleClass {
@Singletone
@Provide
public TestClass provideTestClass() {
return new TestClass("Some Text");
}
}
Upvotes: 0