首页 > 技术文章 > Dragger2学习笔记

lanlengran 2018-08-14 13:47 原文

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的官网, 官网传送门

 

而经过我自己的对比发现该库的以下好处

  1. 添加新的activity和presenter的时候,不需要修改Component,并声明自己的方法
  2. 不需要在每个activity手动注入,只需要在baseactivity中调用
AndroidInjection.inject(this);

就行了,子activity只需要通过泛型把需要加载的presenter类传递过去,就不必再考虑任何细节了

 

集成方法

  1. 首先确保工程已经集成了dragger2的依赖
  2. 在工程添加下面的依赖包
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'
  1. 新建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步即可

后续优化

  1. 上面的方法已经很简单了,但是你可能仍然觉得比较冗余。所以我们仍然可以优化其中的方法。我们可以在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 {

}

这样是不是变得更加方便注入了?

  1. 有人肯定会说,那假如我的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的构造函数包含参数的注入

推荐阅读