How can I create ViewModel containing DAO object in Dager 2? - java

I create android ViewModel in Activity:
EventViewModel model = ViewModelProviders.of(this).get(EventViewModel.class);
For this I create EventViewModel :
public class EventViewModel extends ViewModel {
private final EventDao eventDao;
public EventViewModel(EventDao eventDao) {
this.eventDao = eventDao;
}
public void createEvent(final Event event) {
new Thread(new Runnable() {
#Override
public void run() {
eventDao.insert(event);
}
}).start();
}
}
I learned that I must create custom factory in order to inject my EventDao to EventViewModel. Ok, let's say i did it.
public class ViewModelFactory implements ViewModelProvider.Factory {
private final EventDao eventDao;
#Inject
public ViewModelFactory(EventDao eventDao) {
this.eventDao = eventDao;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if (modelClass == EventViewModel.class) {
return (T) new EventViewModel(eventDao);
}
return null;
}
}
but what to do next? I see several ways. If belive to examples from google I must do next in MyActivity:
EventViewModel model = ViewModelProviders.of(this, new ModelFactory(eventDao)).get(EventViewModel.class);
1) But where do i get eventDao in MyActivity?
2) Do I need create custom ModelFactory for each ViewModel if it use dao class in?
I use Dagger 2 and I just want understand how can I create ViewModel with DAO and use this ViewModel in MyActivity?

You inject ViewModelFactory in the activity. ViewModelFactory will get EventDao through constructor injection. You pass the injected ViewModelFactory instance say viewModelFactory to ViewModelProviders
EventViewModel model = ViewModelProviders.of(this, viewModelFactory).get(EventViewModel.class);

Related

Inject a ViewModel in a BottomSheetDialogFragment JAVA

I'm using dagger2 in my application and I'm trying to inject a ViewModel into BottomSheetDialogFragment but I don't know how.
I have the BaseApplication class like this:
public class BaseApplication extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent
.builder()
.application(this)
.build();
}
}
And the ViewModelFactory:
#Module
public abstract class ViewModelFactoryModule {
#Binds
public abstract ViewModelProvider.Factory mBindViewModelFactory(ViewModelProviderFactory mModelProviderFactory);
}
When I try to inject the viewmodel inside the BottomSheetDialogFragment it shows null exception
public class BottomSheetMoreOptions extends BottomSheetDialogFragment {
#Inject
FeedViewModel ViewModel;
}
The ViewModel constructor is:
#Inject
public FeedViewModel(#Named("notificationsRef") DatabaseReference mRef) {
Log.d(TAG, "HomeViewModel: is ready...");
this.mRef = mRef;
}
Actually to load the bottom sheet I'm passing the view model in its constructor:
BottomSheetMoreOptions bottomSheetMoreOptions = new BottomSheetMoreOptions(model.getFeed().getId(), viewModel);
bottomSheetMoreOptions.show(requireActivity().getSupportFragmentManager(),
"ModalBottomSheet");
Any help please in Java?

Android Dagger2, Singleton cross Component

i have a problem with Singleton with the Dagger2 library for Android.
My problem is im using the #Singleton but getting two different objects =[
i Have 2 Components and 2 Modules:
DispatcherComponent which includes the DispatcherModule class that provides a Dispatcher.
the Dispatcher needs instance UserStore which is provided by StoreModule.
#Singleton
#Component(modules={AppModule.class, StoreModule.class, DispatcherModule.class})
public interface DispatcherComponent {
void inject(SomeClass someClass);
}
and the DispatcherModule.class is as follows
#Module
public class DispatcherModule {
#Provides
#Singleton
public Dispatcher provideDispatcher(UserStore store) {
Log.d("DEBUG", "userStore : " + store.toString());
return new Dispatcher(store);
}
and now the StoreComponent.class
#Singleton
#Component(modules={AppModule.class, StoreModule.class})
public interface StoreComponent {
void inject(SomeOtherClass otherClass);
}
and StoreModule.class
#Module
public class StoreModule {
#Provides
#Singleton
public UserStore provideUserStore() {
return new UserStore();
}
now when im trying to inject UserStore im getting two different objects =/
public class SomeOtherClass extends Acitivity {
#Inject UserStore mStore;
public void onCreate(Bundle savedInstance) {
StoreComponent comp = ((MyApp) getApplication).getStoreComponent();
comp.inject(this);
Log.d("DEBUG", "userStore2 :" + mStore.toString());
}
}
public class SomeClass {
#Inject Dispatcher mDispatcher;
public SomeClass (Application application) {
((MyApp) application).getDispatcherComponent().inject(this);
}
and last, this is how i create the components:
public class MyApp extends Application {
public void onCreate() {
StoreModule store = new StoreModule();
StoreComponent storeComponent = DaggerStoreComponent.builder().appModule(new AppModule(this)).storeModule(storeModule).build();
DispatcherComponent disComp = DaggerDispatcherComponent.builder().appModule(new AppModule(this)).storeModule(storeModule).dispatcherModule(new DispatcherModule()).build();
}
now, when im running the Application, i get 2 different objects ! can someone help me ? how should i fix it? i dont want to have a god component..
THanks!
Note that #Singleton dost not make the object to be singleton actually, instead, it just use the DoubleCheck class to cache which is hold by the component impl generated by dagger. Check DaggerDispatcherComponent for more detail.
For this case, you can change StoreModule like below:
#Module
public class StoreModule {
private UserStore mStore;
#Provides
#Singleton
public UserStore provideUserStore() {
return getStore();
}
private UserStore getStore() {
//lazy initialized and make sure thread safe
if (null == mStore) {
#synchronized(StoreModule.class) {
if (null == mStore) {
mStore = new UserStore();
}
}
}
return mStore;
}
}

Injecting into a POJO with dagger

I have a simple situation here which I am not able to get around (since today is my second day with dagger).
I have a RepositoryManager class the intent of which is to house all repositories like(StudentRepo , TeacherRepo etc etc)
This is my RepositoryManager
public class RepositoryManager {
private static RepositoryManager INSTANCE = null;
#Inject
StudentRepo studentRepo;
#Inject
TeacherRepo teacherRepo;
private final List<Repository> repositories;
private Context context;
#Inject
public RepositoryManager(Context context) {
this.repositories = new ArrayList<>();
this.context = context;
addRepositories();
}
private void addRepositories() {
addRepository(studentRepo);
addRepository(teacherRepo);
}
I understand why my studentRepo and teacherRepo are null here. It is because I have not asked Dagger to fetch them for me . I believe I am missing some very important aspect of Dagger here in which we can explicitly fetch instances of our desired objects.
The StudentRepo btw has its own module and I can easily pull it out in an activity.
My question is just how to fetch instances in a non activity class.
my AppComponent
#Singleton
#Component(modules =
{
AndroidInjectionModule.class,
ApplicationModule.class,
ActivityBindingModule.class,
RepositoryModule.class})
public interface AppComponent extends AndroidInjector<ChallengerHuntApplication> {
RepositoryManager exposeRepositoryManager();
#Component.Builder
interface Builder {
#BindsInstance
AppComponent.Builder application(Application application);
AppComponent build();
}
}
RepositoryModule
#Module(includes = SystemRepositoryModule.class)
public class RepositoryModule {
}
Student Repository Module
#Module
public class StudentRepositoryModule {
#Singleton
#Provides
#Local
public StudentDataSource provideStudentLocalDataSource(Context context) {
return new StudentLocalDataSource(context);
}
#Singleton
#Provides
#Remote
public StudentDataSource provideStudentRemoteDataSource(Context context) {
return new StudentRemoteDataSource();
}
}

Dagger + MVP - Problems injecting Presenter in Model

I'm having problems with the dagger dependency cycle, and despite looking for hours, I can not find the solution. I think it's my idea of architecture. What could be wrong? I'm using Dagger 2.11.
Following the codes
Inicio.java
public class Inicio extends BaseFragment implements InicioMvpView {
#Inject
InicioMvpPresenter inicioPresenter;
#Inject
MainMvpPresenter<MainMvpView> mainPresenter;
//...
InicioComponent.java
#Subcomponent(modules = {InicioModule.class})
public interface InicioComponent extends AndroidInjector<Inicio> {
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<Inicio> {
}
}
InicioModel.java
public class InicioModel implements InicioMvpModel{
#Inject
InicioMvpPresenter inicioPresenter;
#Inject
public InicioModel() {
}
#Override
public void recuperarAgendamentos() {
//...
inicioPresenter.atualizarListaAgendamentos(agendamentos);
}
}
InicioModule.java
#Module
public class InicioModule {
#Provides
InicioMvpView provideInicioView(Inicio inicioFragment){
return inicioFragment;
}
#Provides
InicioMvpPresenter provideInicioPresenter(
InicioPresenter presenter) {
return presenter;
}
#Provides
InicioMvpModel provideInicioModel(InicioModel inicioModel) {
return inicioModel;
}
}
InicioPresenter.java
public class InicioPresenter implements InicioMvpPresenter{
#Inject
InicioMvpModel inicioModel;
#Inject
InicioMvpView inicioMvpView;
#Inject
public InicioPresenter() {
}
#Override
public void recuperarAgendamentos(Bundle savedInstanceState) {
//..
}
}
Your problem is that you trying to solve a ciclic dependency with Dagger and Dagger doesn't solve this problem.
This can be corrected in your architecture. Just pass a callback to your model instead of passing the Presenter to the Model.
This this:
public class InicioModel implements InicioMvpModel{
#Inject
public InicioModel() {
}
#Override
public void recuperarAgendamentos(Presenter inicioPresenter) {
//...
inicioPresenter.atualizarListaAgendamentos(agendamentos);
}
}
That's it. Just pass the presenter as a parameter in your methods in your model. This makes the communication less coupled.
You can also take a look for RxJava, it removes the need to pass the presenter in the method. Link: https://github.com/ReactiveX/RxJava
There is also a good implementation to follow for MVP by Antonio Leiva:
https://github.com/antoniolg/androidmvp

Dagger2 Inject an Interactor into my Presenter

I'm trying to setup an MVP application, I want to Inject my interactor into Presenter Class instead of using the new keyword.
See Example below:
// Example presenter Implementation
public class ExamplePresenterImpl implements ExamplePresenter{
private final Application application;
private ExampleView exampleView;
private ExampleInteractorImpl interactor;
public ExamplePresenterImpl(Application application){
this.application = application;
// I WANT TO GET RID OF THIS AND INJECT INSTEAD.
interactor = new ExampleInteractorImpl(application);
}
#Override
public void setView(ExampleView exampleView){
this.exampleView = exampleView;
}
public void callInteractorMethod(){
// call Fetch method from Interactor
interactor.fetchData();
}
}
// Interactor
public class ExampleInteractorImpl implements ExampleInteractor {
private final Application application;
public ExamplePresenterImpl(Application application){
this.application = application;
}
public List<String> fetchData(){
// return value to the called function
}
}
You could pass the interactor into the constructor of the presenter :
public class MyPresenterImpl implements MyPresenter {
private MyView view;
private MyInteractor interactor;
public MyPresenterImpl(MyView view, MyInteractor interactor) {
this.view = view;
this.interactor = interactor;
}
}
Then in your module :
#Singleton #Provides
public MyInteractor provideMyInteractor(Dependencies...){
return new MyInteractorImpl(your_dependencies);
}
#Singleton #Provides
public MyPresenter provideMyPresenter(MyView view, MyInteractor interactor){
return new MyPresenterImpl(view, interactor);
}
Or you could annotate both Presenter and Interactor constructors with #Inject annotation.
I made an example with a simple login page, you can take a look at it if you need :
https://github.com/omaflak/Dagger2-MVP
You should inject presenter into View(e.g. into Activity) class. Create a module like ExampleModule and a component like ExampleComponent, which will provide the presenter. Presenter should have a constructor that expects all needed dependencies. In this example, dependencies are Application and the interactor

Categories

Resources