I am trying to implement new architecture (MVVM + RxJava2 + Dagger2 + Retrofit) in my existing project. I have set up whole above architecture and tested on HomeActivity. Dependencies injected in HomeViewModel. So Now I was trying to inject dependencies same as HomeViewModel in a FollowingViewModel of FollowingFragment which is a container Fragment of HomeActivity.But injected dependencies always return null(Not Initiziling).
I am following this project riggaroo/android-arch-components-date-countdown to Inject dependencies but in this sample, only activities are used no fragment. So I don't know what is happening and who to inject deps in multiple ViewModels.
Here is code for some important classes to understand:
AppApplication.class
public class AppApplication extends MultiDexApplication implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
#Override
public void onCreate() {
...........................
AppInjector.init(this)
..........................
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}
AppInjector.class
public class AppInjector {
private AppInjector() {
}
public static void init(AppApplication appApplication) {
DaggerAppComponent.builder()
.application(appApplication)
.build()
.inject(appApplication);
appApplication
.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
handleActivity(activity);
}
});
}
private static void handleActivity(Activity activity) {
if (activity instanceof HasSupportFragmentInjector) {
AndroidInjection.inject(activity);
}
if (activity instanceof FragmentActivity) {
((FragmentActivity) activity).getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(
new FragmentManager.FragmentLifecycleCallbacks() {
#Override
public void onFragmentCreated(FragmentManager fm, Fragment f,
Bundle savedInstanceState) {
if (f instanceof Injectable) {
AndroidSupportInjection.inject(f);
}
}
}, true);
}
}
}
AppComponent.class
#Singleton
#Component(modules = {AndroidSupportInjectionModule.class,ActivityBuilderModule.class, AppModule.class, NetworkModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(AppApplication application);
AppComponent build();
}
void inject(AppApplication app);
AppModule.class
#Module(includes = { ViewModelModule.class})
public class AppModule {
#Provides
Context provideContext(AppApplication application) {
return application.getApplicationContext();
}
}
ActivityBuilderModule.class
#Module
public abstract class ActivityBuilderModule {
#ContributesAndroidInjector(modules = FragmentBuildersModule.class)
abstract HomeActivity bindHomeActivity();
}
FragmentBuildersModule.class
#Module
public abstract class FragmentBuildersModule {
#ContributesAndroidInjector
abstract FollowingListFragment contributeFollowingListFragment();
}
ViewModule.class
#Module
public abstract class ViewModelModule {
#Binds
#IntoMap
#ViewModelKey(FollowingViewModel.class)
abstract ViewModel bindFollowingViewModel(FollowingViewModel followingViewModel);
#Binds
#IntoMap
#ViewModelKey(HomeViewModel.class)
abstract ViewModel bindHomeViewModel(HomeViewModel homeViewModel);
#Binds
abstract ViewModelProvider.Factory bindViewModelFactory(MyViewModelFactory factory);
}
NetworkModule.class
#Module
public class NetworkModule {
public NetworkModule(){}
#Provides
#Singleton
CompositeDisposable getCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
#Singleton
Retrofit provideCall() {
// OKHttps and Retrofit code...
}
#Provides
#Singleton
#SuppressWarnings("unused")
public ApiCallInterface providesNetworkService(
Retrofit retrofit) {
return retrofit.create(ApiCallInterface.class);
}
#Provides
#Singleton
#SuppressWarnings("unused")
public Repository providesService(
ApiCallInterface networkService) {
return new Repository(networkService);
}
}
MyViewModelFactory.class
#Singleton
public class MyViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
#Inject
public MyViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
this.creators = creators;
}
#SuppressWarnings("unchecked")
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Provider<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("unknown model class " + modelClass);
}
try {
return (T) creator.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
This class is used to create Instances of all viewModels. I have debugged and found only HomeViewModel instance is creating.
Now I have created HomeViewModel which is called from HomeActivity. Which is working fine. Now same implementaion is done in FollowingFragment but doesn't work. Let me show you how I have initialized FollowViewModel from FollowingListFragment.class
public class FollowingListFragment extends BaseFragment implementsInjectable {
#Inject
MyViewModelFactory myViewModelFactory;
private FollowingViewModel followingViewModel;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = getActivity();
followingViewModel = ViewModelProviders.of(this, plownsViewModelFactory)
.get(FollowingViewModel.class);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_following_list, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
followingViewModel.getFollowings(id,curser);
}
}
Here is FollowingViewModel.class
public class FollowingViewModel extends ViewModel {
#Inject
Repository service;
#Inject
CompositeDisposable subscriptions;
#Inject
public FollowingViewModel() {
}
/*void setService(Repository service){
this.service = service;
}*/
void getFollowings(String id,String curser) {
if(service!=null) { **//HERE SERVICE RETURNS NULL**
Disposable subscription = service.getFollowings(id, curser, new IResponseCallback<FollowingResponse.FollowingResult>() {
#Override
public void onSuccess(FollowingResponse.FollowingResult followingResult) {
}
#Override
public void onError(Throwable throwable) {
}
});
subscriptions.add(subscription);
}else {
Log.d("FollowViewModel", "Service is null " );
}
}
Here is HomeActivity and HomeViewModel class code which is working fine.
HomeActivity.class
public class HomeActivity extends BaseActivity implements HasSupportFragmentInjector, Injectable {
#Inject
DispatchingAndroidInjector<Fragment> supportFragmentInjector;
#Inject
MyViewModelFactory viewFactory;
HomeViewModel homeViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
homeViewModel = ViewModelProviders.of(this,viewFactory).get(HomeViewModel.class);
homeViewModel.getFollowings("xyx",null);
}
#Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return supportFragmentInjector;
}
}
HomeViewModel.class
public class HomeViewModel extends ViewModel {
#Inject
Repository service;
#Inject
CompositeDisposable subscriptions;
#Inject
public HomeViewModel() {
}
void getFollowings(String id,String curser) {
if(service!=null) { **// Returing null service**
}
}else {
Log.d("FollowViewModel", "Service is null " );
}
}
}
Related
I setup the MVVM architecture with retrofit and dagger2 but when i run i found this exception
error: [ComponentProcessor:MiscError]
dagger.internal.codegen.ComponentProcessor was unable to process this
interface because not all of its dependencies could be resolved. Check
for compilation errors or a circular dependency with generated code.
AppModule.java
#Module(subcomponents = ViewModelSubComponent.class)
public class AppModule {
#Singleton
#Provides
ApiService provideService(OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.baseUrl(BaseRequest.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build()
.create(ApiService.class);
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
#Singleton
public StethoInterceptor getSteltho() {
return new StethoInterceptor();
}
#Provides
#Singleton
OkHttpClient provideOkHttpClient(Application application, StethoInterceptor stethoInterceptor, HttpLoggingInterceptor httpLoggingInterceptor) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.connectTimeout(CommonUtils.TIMEOUT_IN_SEC, TimeUnit.SECONDS);
okHttpClient.readTimeout(CommonUtils.TIMEOUT_IN_SEC, TimeUnit.SECONDS);
okHttpClient.addInterceptor(getIntercepter(application));
if (BuildConfig.DEBUG) {
okHttpClient.addNetworkInterceptor(stethoInterceptor);
okHttpClient.interceptors().add(httpLoggingInterceptor);
}
return okHttpClient.build();
}
public Interceptor getIntercepter(final Application application) {
Interceptor headerAuthorizationInterceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
if (!CommonUtils.isNetworkConnected(application)) {
Request request = chain.request();
CacheControl cacheControl = new CacheControl.Builder().maxStale(1, TimeUnit.DAYS).build();
request = request.newBuilder().cacheControl(cacheControl).build();
String rawJson = chain.proceed(request).body().string();
Log.e("TAG", String.format("req response cache raw JSON response is: %s", rawJson));
return chain.proceed(request);
} else {
CacheControl cacheControl = new CacheControl.Builder().maxAge(1, TimeUnit.HOURS).build();
Request.Builder request = chain.request().newBuilder();
request.addHeader("Accept", "application/json");
//request.addHeader("Authorization", mAuth);
request.header("Cache-Control", "public, max-age=" + 90);
request.header(CACHE_CONTROL, cacheControl.toString());
Response response = chain.proceed(request.build());
return response;
}
}
};
return headerAuthorizationInterceptor;
}
#Provides
#Singleton
public HttpLoggingInterceptor httpLoggingInterceptor() {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return httpLoggingInterceptor;
}
/*#Singleton
#Provides
ProjectRepository getrepository() {
return new ProjectRepository();
}*/
#Singleton
#Provides
ViewModelProvider.Factory provideViewModelFactory(ViewModelSubComponent.Builder viewModelSubComponent) {
return new ViewModelFactory(viewModelSubComponent.build());
}
MainActivityModule.java
#Module
public abstract class MainActivityModule {
#ContributesAndroidInjector(modules = FragmentBuildersModule.class)
public abstract MainActivity contributeMainActivity(); // #ContributesAndroidInjector(modules = FragmentBuildersModule.class)
}
FragmentBuildersModule.ktx
#Module
abstract class FragmentBuildersModule {
#ContributesAndroidInjector
internal abstract fun contributeHomeFragment(): HomeFragment
//#ContributesAndroidInjector
//abstract SeriesFragment contributeSeriesFragment();
}
ViewModelFactory.java
#Singleton
public class ViewModelFactory implements ViewModelProvider.Factory {
private final ArrayMap<Class, Callable<? extends ViewModel>> creators;
#Inject
public ViewModelFactory(ViewModelSubComponent viewModelSubComponent) {
creators = new ArrayMap<>();
// View models cannot be injected directly because they won't be bound to the owner's view model scope.
creators.put(ProjectViewModel.class, () -> viewModelSubComponent.homeViewModel());
// creators.put(ProjectListViewModel.class, () -> viewModelSubComponent.projectListViewModel());
}
#Override
public <T extends ViewModel> T create(Class<T> modelClass) {
Callable<? extends ViewModel> creator = creators.get(modelClass);
if (creator == null) {
for (Map.Entry<Class, Callable<? extends ViewModel>> entry : creators.entrySet()) {
if (modelClass.isAssignableFrom(entry.getKey())) {
creator = entry.getValue();
break;
}
}
}
if (creator == null) {
throw new IllegalArgumentException("Unknown model class " + modelClass);
}
try {
return (T) creator.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
AppComponent.java
#Singleton
#Component(modules = {AndroidInjectionModule.class, AppModule.class, MainActivityModule.class})//, MainActivityModule.class
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MyApplication appApplication);
}
AppInjector.java
public class AppInjector {
private static Application application;
private AppInjector() { }
public static void init(MyApplication appApplication) {
application = appApplication;
DaggerAppComponent.builder().application(appApplication).build().inject(appApplication);
appApplication.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
handleActivity(activity);
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
private static void handleActivity(Activity activity) {
if (activity instanceof HasSupportFragmentInjector) {
AndroidInjection.inject(activity);
}
if (activity instanceof FragmentActivity) {
((FragmentActivity) activity).getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
#Override
public void onFragmentCreated(FragmentManager fm, Fragment fragment, Bundle savedInstanceState) {
if (fragment instanceof Injectable) {
AndroidSupportInjection.inject(fragment);
}
}
}, true);
}
}
}
MyApplication.java
public class MyApplication extends Application implements HasActivityInjector {
private static PrefManager mPref;
private static MyApplication myApplication;
private Context context;
//private String dbUrl = "";
#Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
public static MyApplication getInstance() {
return myApplication == null ? new MyApplication() : myApplication;
}
#Override
public void onCreate() {
super.onCreate();
this.context = this;
MultiDex.install(this);
AppInjector.init(this);
Fresco.initialize(this);
RemoteConfig.initConfig();
mPref = new PrefManager(this);
debugToolsInitilization();
}
#Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
Throw exception when i add MainActivityModule module
I have an application (module + component) where
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(App app);
Serializer getSerializer();
ListOfCallingLists getListOfCallingLists();
Context getContext();
App getApp();
}
And
#Module
public class AppModule {
private final App app;
public AppModule(App app) {
this.app = app;
}
#Provides
Serializer provideSerializer() {
return new BinarySerializer();
}
#Provides
Context provideContext() {
return app;
}
#Provides
App provideApp() {
return app;
}
}
And
#Singleton
public class ListOfCallingLists implements Serializable {
...
#Inject
public ListOfCallingLists(Context context,
Serializer serializer) {
this.serializer = serializer;
...
}
}
And App is the application, I registered it in manifest:
public class App extends Application {
private AppComponent appComponent;
public static App get(Context context) {
return (App) context.getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
if (appComponent == null)
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
appComponent.inject(this);
}
public AppComponent getComponent() {
return appComponent;
}
}
And finally the activity:
public class CallListsActivity extends AppCompatActivity {
#Inject
ListOfCallingLists list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
#Override
public void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// list here is null why?
}
}
In your AppComponent you need to add:
void inject(CallListsActivity callListActivity);
And in your CallListsActivity's onCreate() you need to tell how is your CallListsActivity injected.
For example, build your AppComponent and inject the activity, or you can use the new android injector: https://google.github.io/dagger/android.html
How can I provide activity context in mainModule class ? Thanks! The code looks like this:
#Singleton
#Component(modules = {AndroidInjectionModule.class, AppModule.class, ActivityBuilder.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MvmApp app);
}
Activtity builder:
#Module
public abstract class ActivityBuilder {
#ContributesAndroidInjector(modules = {MainModule.class})
abstract MainActivity bindMainActivity();
}
And I have an appModule, and a module for each activity:
#Module
public class AppModule {
#Provides
#Singleton
#ApplicationContext
Context provideContext(Application application) {
return application;
}
#Provides
#Singleton
DataManager provideDataManager(AppDataManager appDataManager) {
return appDataManager;
}
#Provides
#DatabaseInfo
String provideDatabaseName() {
return "carDatabase";
}
#Provides
#Singleton
AppDataBase provideAppDatabase(#DatabaseInfo String dbName, #ApplicationContext Context context) {
return Room.databaseBuilder(context, AppDataBase.class, dbName)
.build();
}
#Provides
#Singleton
DbHelper provideDbHelper(AppDbHelper appDbHelper) {
return appDbHelper;
}
}
AppClass:
public class MvmApp extends Application implements HasActivityInjector {
#Inject
DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.application(this)
.build()
.inject(this);
}
#Override
public DispatchingAndroidInjector<Activity> activityInjector() {
return activityDispatchingAndroidInjector;
}
}
All my activities extends a base activity which inject the Dagger dependecies.
public abstract class BaseActivity extends AppCompatActivity implements MvpView {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidInjection.inject(this);
}
}
In mainModule I need to provide the context of the activity.
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter( #ActivityContext Context context) {
return new CarAdapter(context);
}
}
The solution was:
#Module
public class MainModule {
#Provides
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
CarAdapter provideCarAdapter(MainActivity activity) {
return new CarAdapter(activity);
}
}
For people facing a similar issue, I've made a project with Kotlin, and the new android-dagger extension with a lengthy explanation on how things work over here: https://github.com/Obaied/BareBonesAndroidDagger
Here is my simple app(mobile client for one of the banks in my country). Everything was good until I injected my MapService service to the MapActivity. I don't understand why it doesn't work because the same things work perfectly for MainActivity with MainService - configurations are very similar.
Here is hierarchy:
App
^ ^
MainActivity(may call Map) MapActivity
^ ^
MainFragment DepartmentFragment
Here are major components:
App
public class App extends DaggerApplication {
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().application(this).create(this);
}
}
#Module
public abstract class ActivityBuilder {
#Binds
#IntoMap
#ActivityKey(MapActivity.class)
public abstract AndroidInjector.Factory<? extends Activity> bindMapActivity(MapActivityComponent.Builder builder);
#Binds
#IntoMap
#ActivityKey(MainActivity.class)
public abstract AndroidInjector.Factory<? extends Activity> bindMainActivity(MainActivityComponent.Builder builder);
}
#Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuilder.class
})
public interface AppComponent extends AndroidInjector<App> {
#Component.Builder
public abstract class Builder extends AndroidInjector.Builder<App> {
#BindsInstance
public abstract Builder application(Application application);
public abstract AppComponent build();
}
}
#Module(subcomponents = {
MainActivityComponent.class,
MapActivityComponent.class
})
public class AppModule {
private static final String MTBANK_API_URL = "https://www.mtbank.by";
#Provides
public Context context(Application application) {
return application;
}
#Provides
public Retrofit xmlHttpAdapter() {
return new Retrofit.Builder()
.baseUrl(MTBANK_API_URL)
.client(new OkHttpClient())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
}
#Provides
public MtbClient mtbClient(Retrofit retrofit) {
return retrofit.create(MtbClient.class);
}
}
Map Activity
public class MapActivity extends DaggerActivity implements OnMapReadyCallback {
#Inject
MapService mapService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
...
}
#Override
public void onMapReady(GoogleMap googleMap) {
....
}
}
#Subcomponent(modules = {MapActivityModule.class})
public interface MapActivityComponent extends AndroidInjector<MapActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MapActivity> {
}
}
#Module
public abstract class MapActivityModule {
#Provides
MapService mapService() {
return new MapService();
}
}
Main Activity
public class MainActivity extends DaggerActivity implements MainActivityContract.View, MainFragment.OnClickListener {
#Inject
MainService mapService;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
#Override
public void onDepartmensClick() {
...
}
}
#Subcomponent(modules = {MainActivityModule.class, MainFragmentsProvider.class})
public interface MainActivityComponent extends AndroidInjector<MainActivity> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainActivity> {
}
}
#Module(subcomponents = {DepartmentFragmentComponent.class, MainFragmentComponent.class})
public abstract class MainActivityModule {
#Provides
public static MainService mapService() {
return new MainService();
}
}
#Module
public abstract class MainFragmentsProvider {
#Binds
#IntoMap
#FragmentKey(DepartmentsFragment.class)
public abstract AndroidInjector.Factory<? extends Fragment> bindDepartmentsFragment(DepartmentFragmentComponent.Builder builder);
#Binds
#IntoMap
#FragmentKey(MainFragment.class)
public abstract AndroidInjector.Factory<? extends Fragment> bindMainFragment(MainFragmentComponent.Builder builder);
}
public class MainPresenter implements MainActivityContract.Presenter {
#Inject
public MainPresenter() {
}
}
public class MainService {
}
public interface MainActivityContract {
interface View {
}
interface Presenter {
}
}
Main Fragment
public class MainFragment extends DaggerFragment {
public interface OnClickListener {
void onDepartmensClick();
}
#BindView(R.id.departmens_button)
Button departmensButton;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.main_activity_fragment, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
...
}
}
#Subcomponent(modules = {MainFragmentModule.class})
public interface MainFragmentComponent extends AndroidInjector<MainFragment> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MainFragment> {
}
}
#Module
public class MainFragmentModule {
}
Department Fragment
public class DepartmentsFragment extends DaggerFragment implements DepartmentFragmentContract.View {
#Inject
Context context;
#Inject
DepartmentFragmentContract.Presenter presenter;
#Inject
DepartmentService departmentService;
#Override
public void onViewCreated(View fragment, #Nullable Bundle savedInstanceState) {
super.onViewCreated(fragment, savedInstanceState);
...
}
}
#Subcomponent(modules = {DepartmentFragmentModule.class})
public interface DepartmentFragmentComponent extends AndroidInjector<DepartmentsFragment> {
#Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<DepartmentsFragment> {
}
}
public interface DepartmentFragmentContract {
interface View {
void displayData(RateInfo rateInfo);
void showMessage(String message);
void displayDepartments(List<Department> departments);
void fillInCities(List<String> cities);
void showAtMap(Department department);
void showDepartmentsRates(Department department);
}
interface Presenter {
void loadRatesInfo();
void showDepartmentLocation(Department department);
void showDepartmentsRates(Department department);
void filterDepartmentsByText(CharSequence text);
void filterDepartmentsByCityId(int id);
void resetCity();
}
}
#Module
public class DepartmentFragmentModule {
#Provides
public DepartmentFragmentContract.View view(DepartmentsFragment fragment) {
return fragment;
}
#Provides
public DepartmentFragmentContract.Presenter presenter(DepartmentPresenter rateInfoPresenter) {
return rateInfoPresenter;
}
#Provides
public DepartmentService myService() {
return new DepartmentService();
}
}
public class DepartmentPresenter implements DepartmentFragmentContract.Presenter {
private final DepartmentFragmentContract.View view;
private final MtbClient mtbApi;
#Inject
public DepartmentPresenter(DepartmentFragmentContract.View view,
MtbClient mtbClient) {
this.view = view;
this.mtbApi = mtbClient;
}
...
}
public class DepartmentService {
}
Here is the stack trace. I see the error message but cannot catch up why it says it.
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.slesh.mtbbank/com.slesh.mtbbank.ui.map.MapActivity}:
java.lang.IllegalStateException:
com.slesh.mtbbank.ui.map.MapActivityModule must be set
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2449)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2509)
at android.app.ActivityThread.access$1000(ActivityThread.java:153)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5529)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Caused by: java.lang.IllegalStateException:
com.slesh.mtbbank.ui.map.MapActivityModule must be set
at
com.slesh.mtbbank.DaggerAppComponent$MapActivityComponentBuilder.build(DaggerAppComponent.java:220)
at
com.slesh.mtbbank.DaggerAppComponent$MapActivityComponentBuilder.build(DaggerAppComponent.java:211)
at
dagger.android.AndroidInjector$Builder.create(AndroidInjector.java:68)
at
dagger.android.DispatchingAndroidInjector.maybeInject(DispatchingAndroidInjector.java:79)
at
dagger.android.DispatchingAndroidInjector.inject(DispatchingAndroidInjector.java:104)
at dagger.android.AndroidInjection.inject(AndroidInjection.java:61)
at dagger.android.DaggerActivity.onCreate(DaggerActivity.java:36)
at com.slesh.mtbbank.ui.map.MapActivity.onCreate(MapActivity.java:34)
at android.app.Activity.performCreate(Activity.java:6303)
at
android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
at
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2402)
at
android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2509)
at android.app.ActivityThread.access$1000(ActivityThread.java:153)
at
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:5529)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
Could somebody help me?
In your MapActivityModule.java.
Add static to mapService()
#Module
public abstract class MapActivityModule {
#Provides
static MapService mapService() {
return new MapService();
}
}
I want to add an activity as a dependency for one of my classes
class ViewHandler{
#inject public ViewHandler(Myactivity myactivity){
this.activity = myactivity;
}
}
how can I do this without being obstructed by the Activity life cycle
You need to use subscoped components with modules for this.
#Singleton
#Component(modules={SomethingModule.class})
public interface ApplicationComponent {
Something something();
}
#Module
public class SomethingModule {
#Provides
#Singleton
public Something something() {
return new Something();
}
}
#ActivityScope
#Component(dependencies={ApplicationComponent.class}, modules={MyActivityModule.class})
public interface MyActivityComponent extends ApplicationComponent {
ViewHandler viewHandler();
void inject(Myactivity myActivity);
}
#Module
public class MyActivityModule {
private Myactivity myActivity;
public MyActivityModule(Myactivity myActivity) {
this.myActivity = myActivity;
}
#Provides
public Myactivity myActivity() {
return myActivity;
}
#Provides
#ActivityScope
public ViewHandler viewHandler(Myactivity myActivity) {
return new ViewHandler(myActivity);
}
}
public class CustomApplication extends Application {
ApplicationComponent applicationComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.create();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
public class Myactivity extends AppCompatActivity {
MyActivityComponent myActivityComponent;
#Inject
ViewHandler viewHandler;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication customApp = (CustomApplication)getApplicationContext();
this.myActivityComponent = DaggerMyActivityComponent.builder()
.applicationComponent(customApp.getApplicationComponent())
.myActivityModule(new MyActivityModule(this))
.build(); //preserve the state of your dependencies in onSaveInstanceState();
myActivityComponent.inject(this);
}
}
EDIT: Another option is #Subcomponent annotation
#Singleton
#Component(modules={SomethingModule.class})
public interface ApplicationComponent {
Something something();
MyActivityComponent newMyActivityComponent(MyActivityModule myActivityModule);
}
#ActivityScope
#Subcomponent(modules={MyActivityModule.class})
public interface MyActivityComponent {
ViewHandler viewHandler();
void inject(Myactivity myActivity);
}
public class Myactivity extends AppCompatActivity {
MyActivityComponent myActivityComponent;
#Inject
ViewHandler viewHandler;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
CustomApplication customApp = (CustomApplication)getApplicationContext();
this.myActivityComponent = customApp.getApplicationComponent()
.newMyActivityComponent(new MyActivityModule(this));
myActivityComponent.inject(this);
}
}