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);
}
}
Related
My AppComponent
#Singleton
#Component(modules = {SplashModule.class})
public interface AppComponent {
void inject(SplashActivity splashActivity);//this is inject activity
}
Splash Module
#Module
public class SplashModule {
#Provides
#Singleton
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
#Singleton
SplashPresenter provideSplashPresenter(SplashInteract splashInteract){
return new SplashPresenter(splashInteract);//instance SplashPresenter
};
}
Splash Presenter
public class SplashPresenter implements ISplashContract.Presenter {
ISplashContract.View mView;
SplashInteract splashInteract;
public SplashPresenter(SplashInteract splashInteract) {
this.splashInteract =splashInteract;
}
public void bindView(ISplashContract.View mView) {
this.mView = mView;
}
#Override
public void attach() {
this.mView.startAnimation();//start splash animation
}
#Override
public void start(Activity activity) {
this.splashInteract.SplashScreenAnimation(activity);// add interact methods
}
}
Splash Activity
public class SplashActivity extends AppCompatActivity implements ISplashContract.View{
#Inject SplashPresenter splashPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
getAppComponent().inject(this);//call BaseApp DaggerAppComponent
splashPresenter.attach();
splashPresenter.bindView(this);
}
#Override
public void startAnimation() {
this.splashPresenter.start(this);
}
}
Base App
public class BaseApp extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
setUp();
}
private void setUp() {
appComponent = DaggerAppComponent.builder().build();//Call Component in BaseApp
}
public static AppComponent getAppComponent() {
return appComponent;
}
}
Hi Everyone
I am writing a project, I want to use dagger, but I am inexperienced at this. This code gives a NullPointerException error. I could not find what I am doing wrong.
I need help and I will be glad if those who know better than the dagger guide me
In your case, dagger will not know how to provide splashPresenter, either do a constructor Injection or define in the module how SplashPresenter should be created, and remove SpashPresenter from the Component. The module approach should be like so,
#Module
public class SplashModule {
ISplashContract.View mView;
public SplashModule(ISplashContract.View mView) {
this.mView = mView;//add SplashModule view
}
#Provides
#Singleton
public ISplashContract.View provideSplashPresenter(){
return mView;//set this view
}
#Provides
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
SplashPresenter provideSplashPresenter(ISplashContract.View mView, SplashInteract splashInteract){
return new SplashPresenter(mView, splashInteract);//instance SplashPresenter
};
}
And remove inject annotations from SplashPresenter and you will also have to change the signature for its constructor. You can optionally remove Singleton annotation from the code, if the presenter is not supposed to be singleton.
Updates based on comments
public class SplashModule {
#Provides
static SplashInteract provideSplashInteract(){
return new SplashInteract();//instance interact
};
#Provides
SplashPresenter provideSplashPresenter(SplashInteract splashInteract){
return new SplashPresenter(splashInteract);//instance SplashPresenter
};
}
public class SplashPresenter implements ISplashContract.Presenter {
ISplashContract.View mView;
SplashInteract splashInteract;
public SplashPresenter(SplashInteract splashInteract) {
this.splashInteract = splashInteract;
}
public void bindView(ISplashContract.View mView) {
this.mView = mView;
}
#Override
public void attach() {
this.mView.startAnimation();//start splash animation
}
#Override
public void start(Activity activity) {
this.splashInteract.SplashScreenAnimation(activity);// add interact methods
}
}
public class SplashActivity extends AppCompatActivity implements ISplashContract.View{
#Inject SplashPresenter splashPresenter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
getAppComponent().inject(this);//call BaseApp DaggerAppComponent
splashPresenter.bind("the view you want to bind")
splashPresenter.attach();
}
#Override
public void startAnimation() {
this.splashPresenter.start(this);
}
}```
Make sure that you declare your BaseApp in AndroidManifest :
<application
android:name=".fullPathTo.BaseApp"
...
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
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 have a class that's being injected using DI via dagger. However when the activity is destroyed and recreated, the model class seems to contain the data automatically without me insert/repopulating the data.
public class MyApplication extends Application {
private ExpressionFactoryComponent mExpressionFactoryComponent;
#Override
public void onCreate() {
super.onCreate();
// Building dagger DI component
mExpressionFactoryComponent = DaggerExpressionFactoryComponent.builder().
expressionFactoryModule(new ExpressionFactoryModule(new ExpressionFactory(this))).build();
}
}
Module:
#Module
public class ExpressionFactoryModule {
private ExpressionFactory mExpressionFactory;
public ExpressionFactoryModule(ExpressionFactory expressionFactory) {
this.mExpressionFactory = expressionFactory;
}
#Provides
ExpressionFactory provideStringExpressionFactory() {
return mExpressionFactory;
}
}
The one reason for this is that ExpressionFactory is instantiated in MyApplication class and then passed into the constructor of ExpressionFactoryModule while creating ExpressionFactoryComponent. You should pass an Application instance in your module constructor and then create an instance of your class withing a metod with #Provide annotation passing that Application instance in your class's constructor.
This how things should be done with dagger. But to solve your problem you need to create another component class and build the component in an activity if you need to have an instance of your class living withing an activity only.
Here is the solution (ExpressionFactoryComponent is renamed to AppComponent here):
public class MyApplication extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
// Building dagger DI component
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this)).build();
}
public static AppComponent getAppComponent() {
return appComponent;
}
}
#Component(modules = {AppModule.class})
public interface AppComponent {
Application getApplication();
void inject(App application);
}
#Module
public class AppModule {
private Application application;
public AppModule(Application application) {
this.application = application;
}
#Provides
Application provideApplication() {
return application;
}
}
#Component(dependencies = AppComponent.class, modules = {
ActivityModule.class})
public interface ActivityComponent {
void inject(MainActivity activity);
}
#Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
#Provides
Activity provideActivity() {
return activity;
}
#Provides
ExpressionFactory provideStringExpressionFactory(Application application) {
return new ExpressionFactory(application);
}
}
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityComponent activityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(activity))
.appComponent(App.getAppComponent())
.build();
activityComponent.inject(this);
}
}
Let's say I have three Dagger modules:
#Module()
public class MainModule {
private Application application;
public MainModule(Application application) {
this.application = application;
}
#Provides
#Singleton
Application provideApplication() {
return application;
}
#Provides
Something provideSomething(Application application) {
return new Something(application);
}
}
#Module()
public class SubModule1 {
private Activity activity;
public SubModule1(Activity activity) {
this.activity = activity;
}
#Provides
#Singleton
Activity provideActivity() {
return activity;
}
#Provides
SomethingElse provideSomethingElse(Activity activity) {
return new SomethingElse(activity);
}
}
#Module()
public class SubModule2 {
private Activity activity;
public SubModule2(Activity activity) {
this.activity = activity;
}
#Provides
#Singleton
Activity provideActivity() {
return activity;
}
#Provides
Anything provideAnything(Activity activity) {
return new Anything(activity);
}
}
Now assuming I want to do something like this:
public class MyApplication extends Application {
...
#Override
public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(new MainModule(this));
objectGraph.inject(this);
}
}
public class MyActivity1 extends Activity {
...
#Override
public void onCreate() {
super.onCreate();
objectGraph = ((MyApplication) getApplication()).getObjectGraph().plus(new SubModule1(this)
objectGraph.inject(this);
}
}
public class MyActivity2 extends Activity {
...
#Override
public void onCreate() {
super.onCreate();
objectGraph = ((MyApplication) getApplication()).getObjectGraph().plus(new SubModule2(this)
objectGraph.inject(this);
}
}
It also might happen that I have such a class:
public class TestClass {
#Inject
SomethingElse somethingElse;
#Inject
Anything anything;
}
What is the right way to implement this? How should I use includes, addsTo, injects, library, complete and plus()?
I usually set Dagger up as follows:
Extend Application like this:
public class InjectingApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(new MainModule(this));
objectGraph = ObjectGraph.create(new SubModule1(this));
objectGraph = ObjectGraph.create(new ActivityModule());
objectGraph.inject(this);
}
}
Then have a module for adding references to your Activities (called ActivityModule.java in this instance):
#Module(
injects = {
MyActivity1.class,
MyActivity2.class }
) public class ActivityModule { }
Then your Activities will look like this:
public class MyActivity1 extends Activity {
#Inject
Something something;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((InjectingApplication) getApplication()).inject(this);
}
}
Finally, your modules will look like this:
#Module()
public class MainModule {
private Context context;
public MainModule(Context context) {
this.context = context;
}
#Provides
Something provideSomething(Context context) {
return new Something(context);
}
}
#Module()
public class SubModule1 {
private Context context;
public SubModule1(Context context) {
this.context = context;
}
#Provides
SomethingElse provideSomethingElse(Context context) {
return new SomethingElse(context);
}
}