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
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 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);
}
}
Hello so I've been going crazy trying to figure out what I haven't configured properly to get a non null dependency when injecting into a class. Below is my current code
public interface DaggerGraph {
void inject(SplashActivity splashActivity);
}
DaggerGraph to provide interface for injecting
#Singleton
#Component(modules = {MainModule.class})
public interface DaggerComponent extends DaggerGraph {
final class Initializer {
private Initializer() {
}
public static DaggerComponent init(Application app) {
return DaggerDaggerComponent.builder()
.mainModule(new MainModule(app))
.build();
}
}
}
The Dagger component
#Module
public class MainModule {
private final Application app;
public MainModule(Application app) {
this.app = app;
}
#Provides
#Singleton
Application provideApplication() {
return app;
}
#Provides
#Singleton
Resources provideResources() {
return app.getResources();
}
}
The Main Module
public class App extends Application {
private static DaggerComponent daggerComponent;
#Override
public void onCreate() {
super.onCreate();
daggerComponent = DaggerComponent.Initializer.init(this);
}
public static DaggerComponent component() {
return daggerComponent;
}
}
Application
public class SplashActivity extends BaseActivity {
#Inject
Resources resources;
#Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
App.component().inject(this);
}
#Override
protected void onResume() {
super.onResume();
Timber.d(Boolean.toString(resources == null)); //Always true
}
}
In this activity Resources is ALWAYS null and its driving me crazy. Any help is much appreciated.
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);
}
}
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);
}
}