Dragger2学习笔记
dragger2-android
使用这个的意义
使用Dagger2开发Android的话,有一个困难就是android的一些框架类,如Activity和Fragment等,他们的实例化由操作系统完成,如果要想让Dagger2也能很好地注入这些对象,你不得不在生命周期里添加以下代码完成注入过程。
public class FrombulationActivity extends Activity {
@Inject Frombulator frombulator;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// DO THIS FIRST. Otherwise frombulator might be null!
((SomeApplicationBaseType) getContext().getApplicationContext())
.getApplicationComponent()
.newActivityComponentBuilder()
.activity(this)
.build()
.inject(this);
// ... now you can write the exciting code
}
}
这样做存在以下问题:
1.上面的代码要复制粘贴到所有的Activity中,这就会给以后重构代码造成麻烦,你的团队越来越多的人复制上面的代码块,会有越来越少的人知道这块代码的真正用途。 2.更重要的是,它要求请求注射类型(FrombulationActivity )知道它的注射器,既即使它可以通过接口而不是具体的类型完成,但是它打破了依赖注入的核心原则:一个类不应该知道任何关于它是如何注入的。 以上,所以基于Dagger2的,适用于Android开发的Dagger2-Android应运而生。
以上翻译以及以上的代码均来自Dagger2的官网, 官网传送门
而经过我自己的对比发现该库的以下好处
- 添加新的activity和presenter的时候,不需要修改Component,并声明自己的方法
- 不需要在每个activity手动注入,只需要在baseactivity中调用
AndroidInjection.inject(this);
就行了,子activity只需要通过泛型把需要加载的presenter类传递过去,就不必再考虑任何细节了
集成方法
- 首先确保工程已经集成了dragger2的依赖
- 在工程添加下面的依赖包
compile 'com.google.dagger:dagger-android:2.15'
compile 'com.google.dagger:dagger-android-support:2.15' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.15'
- 新建BaseActivity,最少应该具有以下代码
public abstract class BaseActivity<T extends AbstractPresenter> extends AppCompatActivity{
@Inject
protected T mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
AndroidInjection.inject(this);
mPresenter.attachView(this);
super.onCreate(savedInstanceState);
}
}
4.新建BasePresenter,最少应该具有以下代码
public class BasePresenter<T extends BaseActivity> {
protected T mView;
public void attachView(T view) {
this.mView = view;
}
}
5.新建BaseActSubCompoent
@Subcomponent(modules = AndroidInjectionModule.class)
public interface BaseActSubComponent extends AndroidInjector<BaseActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<BaseActivity>{
}
}
6.新建AllActivityModule,以后所有需要注解的类,都需要在此注册,暂时此处只添加了MainActivity,以后如果需要添加其他的Activity,只需要照本宣科即可
@Module(subcomponents = BaseActSubComponent.class)
public abstract class AllActivityModule {
@ContributesAndroidInjector(modules = MainActModule.class)
abstract MainActivity contributeMainActivityInject();
}
7.新建AppModule,用于Application的注入
@Module
public class AppModule {
private final MyApplication application;
public AppModule(MyApplication application) {
this.application = application;
}
@Provides
@Singleton
MyApplication provideApplicationContext() {
return application;
}
}
8.新建Application的compoent,我这里叫AppComponent。
@Singleton
@Component(modules = {AndroidInjectionModule.class,
AppModule.class,
AllActivityModule.class})
public interface AppComponent {
void inject(MyApplication application);
}
9.在自己的Application的oncreate中添加Dragger2的注入,同时,我们还需要让我们的Application实现HasActivityInjector接口。最后我们的Applicaion的代码如下
public class MyApplication extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> mAndroidInjector;
private static MyApplication instance;
@Override
public void onCreate() {
super.onCreate();
DaggerAppComponent.builder()
.appModule(new AppModule(instance))
.build().inject(this);
instance = this;
}
public static MyApplication getInstance() {
return instance;
}
@Override
public AndroidInjector<Activity> activityInjector() {
return mAndroidInjector;
}
}
10.经过上面的步骤,我们基本上已经搭建好最基本的框架了,现在只需要把我们要注入的activity添加进去就行了。假如我们要注入MainActivity。那么我们只需要让我们的Activity继承自BaseActivity即可。具体代码如下 MainActivity
public class MainActivity extends BaseActivity<MainPresenter> {
@Override
protected void onCreate(Bundle savedInstanceState) {
// AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showMsg(String msg){
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
}
同样我们的presenter也是这样操作
public class MainPresenter extends BasePresenter<MainActivity> {
// @Inject
public MainPresenter() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mView.showMsg("哈哈哈哈哈");
}
},1500);
}
}
11.最后我们再新建一个MainActModule
@Module()
public abstract class MainActModule {
@Provides
static MainPresenter provideStudent(){
return new MainPresenter();
}
}
同时把MainActModule在AllActivityModule中予以注册,由于我们在上面已经注册过了,所以就不再赘述了。
这样编译运行以后,就可以看到我们的presenter已经在Activity中注入成功。如果我们要注入新的activity只需要重复第10和11步即可
后续优化
- 上面的方法已经很简单了,但是你可能仍然觉得比较冗余。所以我们仍然可以优化其中的方法。我们可以在Presenter的构造函数上面,添加一个注解标识符@Inject。最终代码如下
public class MainPresenter extends BasePresenter<MainActivity> {
@Inject
public MainPresenter() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mView.showMsg("哈哈哈哈哈");
}
},1500);
}
}
添加了这个注解以后,我们就可以删除我们在MainActModule的方法。使MainActModule最终变成
@Module()
public abstract class MainActModule {
}
这样是不是变得更加方便注入了?
- 有人肯定会说,那假如我的presenter的构造函数是有参数的,那该怎么办。当然,我们也是有方法的。首先我们假设presenter的构造函数需要传递一个student对象过去,那么我们的presenter就变成了这样
public class MainPresenter extends BasePresenter<MainActivity> {
@Inject
public MainPresenter(final Student student) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mView.showMsg("哈哈哈哈哈"+student.toString());
}
},1500);
}
}
那么这里需要的student从哪里来呢?毕竟我们已经在MainActModule中删除了new Presenter的方法。这时候我们就需要改造AppComponent和AppModule了。我们需要在AppComponent中声明返回类型是Student的方法,并在AppModul中实现返回类型是Student的方法
最后AppComponent的代码
@Singleton
@Component(modules = {AndroidInjectionModule.class,
AppModule.class,
AllActivityModule.class})
public interface AppComponent {
void inject(MyApplication application);
MyApplication getContext();
Student getStudent();
}
AppModul的代码
@Module
public class AppModule {
private final MyApplication application;
public AppModule(MyApplication application) {
this.application = application;
}
@Provides
@Singleton
MyApplication provideApplicationContext() {
return application;
}
@Provides
@Singleton
Student provideStudent() {
return new Student();
}
}
这样完成了presenter的构造函数包含参数的注入