Student.java文件
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
在appcomponent包下面,三个文件:AppComponent.java、AppModule.java、PerActivity.java。
AppComponent.java文件
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
Context getApplicationContext();
Student getStudent();
}
@Module
public class AppModule {
private static int count = 0;
private App app;
public AppModule(App app) {
this.app = app;
}
@Provides
@Singleton
Student providerStudent() {
return new Student(23, "jack" + String.valueOf(count++));
}
@Provides
@Singleton
Context providerApplicationContext() {
return app.getApplicationContext();
}
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
ConstructorComponent.java文件
@PerActivity
@Component(modules = ConstructorModule.class)
public interface ConstructorComponent {
void inject(MainActivity mainActivity);
}
ConstructorModule.java文件
@PerActivity
@Module
public class ConstructorModule {
public ConstructorModule() {
}
}
public class App extends Application {
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
public class MainActivity extends AppCompatActivity {
Button btn;
@Inject
Student student;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
DaggerConstructorComponent.builder().appComponent(((App)getApplication()).getAppComponent())
.constructorModule(new ConstructorModule()).build().inject(this);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
test();
}
});
}
private void test() {
Toast.makeText(getApplicationContext(), student.getName() + ", " + student.getAge(), Toast.LENGTH_SHORT).show();
}
}
Error:(14, 10) 错误: com.robot.ddagger.bean.Student cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
com.robot.ddagger.MainActivity.student
[injected field of type: com.robot.ddagger.bean.Student student]
分析这里为什么会出现问题呢?
先看看在dagger2帮我们生成了哪些文件。
AppModule_ProviderApplicationContextFactory.java
AppModule_ProviderStudentFactory.java
DaggerAppComponent.java
MainActivity_MembersInjector.java // 生成这个文件是因为在MainActivity中有@Inject Student student;,如果去掉这句话则不会生成这个文件。
按照dagger2的规则应该也会对应生成,DaggerConstructorComponent.java文件,但是这里并没有生成。
看看错误的提示,翻译一下:不能没有一个@Inject构造函数或从@ Provides-提供或@产生注解方法。
不好理解,还是从生成的MainActivity_MembersInjector.java分析。
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<Student> studentProvider;
public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Student> studentProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert studentProvider != null;
this.studentProvider = studentProvider;
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.student = studentProvider.get();
}
public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Student> studentProvider) {
return new MainActivity_MembersInjector(supertypeInjector, studentProvider);
}
}
可以看到这里有个Provider<Student> studentProvider;,也就是说MainActivity_MembersInjector.java需要这个studentProvider。
这里如果在MainActivity.java中有其他的@Inject XXX xxx,那么也会在MainActivity_MembersInjector.java中产生,Provider<XXX> xxxProvider。
我们也知道DaggerXXXComponent调用inject()函数的时候,将会调用相关的XXX_MembersInjector中的函数。
对应于这里的情况就是DaggerConstructorComponent中的inject()函数,会调用这里的MainActivity_MembersInjector中函数。
首先调用的当然是这里的MainActivity_MembersInjector中的create()了。
那么问题来了,这里的Provider<Student> studentProvider如何从
DaggerConstructorComponent传递给MainActivity_MembersInjector的create()呢?也就是说DaggerConstructorComponent必然自己也有
Provider<Student> studentProvider这个。回到我们的ConstructorComponent.java的定义。
@PerActivity
@Component(modules = ConstructorModule.class)
public interface ConstructorComponent {
void inject(MainActivity mainActivity);
}
@PerActivity
@Module
public class ConstructorModule {
public ConstructorModule() {
}
}
(1)在MainActivity中的@Inject Student student,导致生成了MainActivity_MembersInjector,而且是构造函数带有参数Provider<Student>的。
(2)而我们定义的ConstructorComponent中可以知道,MainActivity是目标类,而ConstructorModule是目标依赖类。
生成的DaggerConstructorComponent的inject到时候会调用MainActivity_MembersInjector类,需要将Provider<Student>传递给
MainActivity_MembersInjector类,但是发现ConstructorModule并没有提供任何有关Provider<Student>的东西。
所以导致DaggerConstructorComponent生成不了。
解决方法也很简单,你需要告诉DaggerConstructorComponent,你提供了Provider<Student>了。
@PerActivity
@Component(dependencies = AppComponent.class, modules = ConstructorModule.class)
public interface ConstructorComponent {
void inject(MainActivity mainActivity);
}
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
Context getApplicationContext();
Student getStudent();
}
这样子DaggerConstructorComponent就可以把Provider<Student>传递给MainActivity_MembersInjector了。
看看生成的DaggerConstructorComponent.java文件:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerConstructorComponent implements ConstructorComponent {
private Provider<Student> getStudentProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerConstructorComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private void initialize(final Builder builder) {
this.getStudentProvider = new Factory<Student>() {
private final AppComponent appComponent = builder.appComponent;
@Override public Student get() {
Student provided = appComponent.getStudent();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable component method");
}
return provided;
}
};
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), getStudentProvider);
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
public static final class Builder {
private ConstructorModule constructorModule;
private AppComponent appComponent;
private Builder() {
}
public ConstructorComponent build() {
if (constructorModule == null) {
this.constructorModule = new ConstructorModule();
}
if (appComponent == null) {
throw new IllegalStateException("appComponent must be set");
}
return new DaggerConstructorComponent(this);
}
public Builder constructorModule(ConstructorModule constructorModule) {
if (constructorModule == null) {
throw new NullPointerException("constructorModule");
}
this.constructorModule = constructorModule;
return this;
}
public Builder appComponent(AppComponent appComponent) {
if (appComponent == null) {
throw new NullPointerException("appComponent");
}
this.appComponent = appComponent;
return this;
}
}
}
重点代码,可以看到这里的studentProvider是AppComponent提供的。并且把studentProvider传递给MainActivity_MembersInjector了。
private void initialize(final Builder builder) {
this.getStudentProvider = new Factory<Student>() {
private final AppComponent appComponent = builder.appComponent;
@Override
public Student get() {
Student provided = appComponent.getStudent();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable component method");
}
return provided;
}
};
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), getStudentProvider);
}
本文资源代码下载 :https://github.com/robotlife/DDaggerDepend