添加依赖
// dagger
implementation 'com.google.dagger:dagger:2.15'
annotationProcessor 'com.google.dagger:dagger-compiler:2.15'
添加代码
添加一个presenter
public class ScanPresenter {
public static final String TAG = "ScanPresenter";
@Inject
public ScanPresenter(Activity activity) {
mActivity = activity;
}
}
记得在构造方法上添加@Inject注解
在activity中使用这个presenter
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
// 添加inject注解,不用通过new来手动实例化
@Inject
ScanPresenter mScanPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
添加ActivityModule用来对外提供activity实例。因为presenter的构造函数需要用到。
@Module
public class MainActivityModule {
private Activity mActivity;
public MainActivityModule(Activity activity) {
mActivity = activity;
}
@Provides
public Activity getActivity() {
return mActivity;
}
}
添加对应的Component用于执行注入操作。也就是注入的入口
@Component(modules = {MainActivityModule.class})
public interface MainActivityComponent {
void inject(MainActivity activity);
ScanPresenter getPresenter();
}
在对应activity中添加注入代码
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Inject
ScanPresenter mScanPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
.mainActivityModule(new MainActivityModule(this))
.build();
mainActivityComponent.inject(this);
}
}
小结:
- 提供实例的注解有
@Inject
,@Module
和@Provides
。其中@Inject
用于构造函数,@Module
和@Provides
用于无法在对应构造函数上添加Inject注解的实例(比如第三方包,android系统类等等)。 - 注入实例的注解
@Inject
- 注解的入口
@Component
,里面需要添加对应的modules或者依赖,这个是执行依赖注入的入口,也就是说对应的类的实例会在这里实例化。也可以在这个接口里通过添加对应返回值的函数来获取这个类型的实例(比如MainActivityComponent中的getPresenter方法)。
多component之间相互依赖
添加retrofit的依赖用来发送网络请求
@Module
public class NetModule {
public String BASE_RUL = "";
@Singleton
@Provides
public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BASE_RUL)
.addConverterFactory(FastJsonConverterFactory.create())
.build();
}
@Singleton
@Provides
public OkHttpClient provideHttpClient() {
return new OkHttpClient.Builder()
.build();
}
}
添加网络接口
public interface TransactionService {
@FormUrlEncoded
@POST("/broadcast-tx")
Call<SendResult> send(@Field("coin_type") String coinType, @Field("signed_tx") String signedData, @Field("origin_data") String originData);
}
提供接口的module
@Module
public class ServiceModule {
@Provides
public TransactionService provideTransaction(Retrofit retrofit) {
return retrofit.create(TransactionService.class);
}
}
添加AppModule用来提供applicationContext,但是现在暂时没用到。
@Module
public class AppModule {
private MyApplication mMyApplication;
public AppModule(MyApplication myApplication) {
mMyApplication = myApplication;
}
@Singleton
@Provides
public MyApplication provideApplication() {
return mMyApplication;
}
}
添加AppComponent
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface AppComponent {
MyApplication application();
Retrofit getRetrofit();
}
在application中实例化这些代码。(先编译一下,生成一些类)
public class MyApplication extends Application {
private AppComponent mAppComponent;
private static MyApplication sContext;
@Override
public void onCreate() {
super.onCreate();
sContext = this;
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
public static MyApplication getContext() {
return sContext;
}
public AppComponent getAppComponent() {
return mAppComponent;
}
}
主要是实例化AppModule这个类。提供application的实例。
添加一个scope
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
添加MainActivityModule
@Module
public class MainActivityModule {
private MainActivity mActivity;
public MainActivityModule(MainActivity activity) {
mActivity = activity;
}
@ActivityScope
@Provides
public MainActivity getActivity() {
return mActivity;
}
}
添加MainActivityComponent
@ActivityScope
@Component(modules = {MainActivityModule.class, ServiceModule.class}, dependencies = {AppComponent.class})
public interface MainActivityComponent {
void inject(MainActivity activity);
}
这里就是一个component依赖另一个component,通过dependencies来表示依赖关系。因为我们的retrofit是需要AppComponent提供的,所以需要添加这个,还有一个需要注意的点是:MainActivityComponent需要的依赖,在AppComponent中需要要提供一个具体的方法,比如这里AppComponent中的Retrofit getRetrofit();
方法,因为这个Retrofit是MainActivityComponent需要的依赖,不然会报错。
在mainActivity中添加注入的入口
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AppComponent appComponent = MyApplication.getContext().getAppComponent();
MainActivityComponent component = DaggerMainActivityComponent.builder()
.appComponent(appComponent)
.mainActivityModule(new MainActivityModule(this))
.build();
component.inject(this);
}
小结
这里有两个点
- 多component依赖的时候,被依赖的component要显示的提供依赖方法,而不是有provides标注或者Inject标注提供了就好了比如这里AppComponent中提供的
getRetrofit
方法。 - 使用dependencies的时候,对于像activity等等有自己的生命周期的,需要用@scope(也就是这里的ActivityScope)限定一下。不然会有报错提示。
生成的代码分析
public final class DaggerMainActivityComponent implements MainActivityComponent {
private ServiceModule serviceModule;
private AppComponent appComponent;
private Provider<MainActivity> getActivityProvider;
看DaggerMainActivityComponent里有三个变量,这三个变量就是在声明DaggerMainActivityComponent在注解里写的,两个是modules, 一个是dependencies,看这三个是如何实例化的?
看builder方法
public static final class Builder {
private MainActivityModule mainActivityModule;
private ServiceModule serviceModule;
private AppComponent appComponent;
private Builder() {}
public MainActivityComponent build() {
if (mainActivityModule == null) {
throw new IllegalStateException(
MainActivityModule.class.getCanonicalName() + " must be set");
}
if (serviceModule == null) {
this.serviceModule = new ServiceModule();
}
if (appComponent == null) {
throw new IllegalStateException(AppComponent.class.getCanonicalName() + " must be set");
}
return new DaggerMainActivityComponent(this);
}
public Builder mainActivityModule(MainActivityModule mainActivityModule) {
this.mainActivityModule = Preconditions.checkNotNull(mainActivityModule);
return this;
}
public Builder serviceModule(ServiceModule serviceModule) {
this.serviceModule = Preconditions.checkNotNull(serviceModule);
return this;
}
public Builder appComponent(AppComponent appComponent) {
this.appComponent = Preconditions.checkNotNull(appComponent);
return this;
}
}
builder里面可以通过方法设置这些实例,但是有些我们没有设置比如ServiceModule,在build方法里,他会检查,如果他可以帮忙实例化的,就实例化(这里直接new出来了ServiceModule),否则会抛出异常进行提示。
有了对应的辅助类的实例,再看是如何注入的,看入口inject函数:
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);
}
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectMScanPresenter(instance, getScanPresenter());
MainActivity_MembersInjector.injectModel(instance, getTransactionModel());
return instance;
}
看这两个方法:
public static void injectMScanPresenter(MainActivity instance, ScanPresenter mScanPresenter) {
instance.mScanPresenter = mScanPresenter;
}
public static void injectModel(MainActivity instance, TransactionModel model) {
instance.model = model;
}
其实就是给对应的变量赋值,这也是为啥@Inject修饰的变量不能是private的。
在看一个方法:
private TransactionService getTransactionService() {
return ServiceModule_ProvideTransactionFactory.proxyProvideTransaction(
serviceModule,
Preconditions.checkNotNull(
appComponent.getRetrofit(),
"Cannot return null from a non-@Nullable component method"));
}
在获取retrofit的时候,是通过AppComponent获取的,这也是为啥被依赖的component需要显示的提供方法,而不是打标注就好了。
他是在什么时机实例化对象的?
由代码可以看到在build的时候会实例化一些辅助类,比如module等等,而在调用inject方法的时候才会去获取并且实例化这些对象。比如获取presenter。
总结:
- @Inject标注在构造方法可以提供注解,标注在变量上表示这个变量需要注入。
- @Module和@provides用于给那些无法打标注的比如第三方包,以及系统去实例化的比如activity等等提供依赖注入。
- @component管理一个依赖集合,也是依赖的入口,可以多个component相互依赖,但是需要显示的提供被依赖的方法。
- 当对应依赖已经提供(通过@inject或者provides)的时候,这个类型可以直接作为参数使用,比如provideRetrofit方法将OkHttpClient作为参数,因为OkHttpClient已经可以提供了。
参考文章:
https://juejin.im/post/58722866128fe1006b33e104
https://www.jianshu.com/p/92f793e76654
https://google.github.io/dagger/android