对Dagger2的使用

对Dagger2的使用

MVP架构模式已经火了一段时间了,在我的项目中也使用到了这种架构,说实话的确使我的项目得到了很大程度的解耦。原来杂糅的代码,维护和修改起来都使人头疼。我接手过一个项目,一个Activity中至少有3000行代码,而问题的根本仅仅是一个参数问题,但耗费的时间和精力却……
好了,回归正题。做过java web一段时间,其中层之间解耦使用的是Spring。通过接口和配置文件实现依赖注入,即接口注入。那么在android开发中,使用到的MVP架构也存在层与层的概念,目前分层架构确实使代码耦合度更低一些。但是还是存在耦合,如:

 private LoginPresenter loginPresenter;
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        ……
        loginPresenter = new LoginPresenterImpl(this);
    }

嗯,这种方式是无可避免的。因为毕竟想拿到Presenter层引用,你就必须使用new操作,不然呢,肯定会抛出空指针啊。好,目标很明确。我们实现的就是不用new,而从外部依赖注入一个实例进来,实现我们的依赖注入(ioc),因为具体如何实现Presenter的初始化并不是view层关心的。接下来要登场的便是Dagger2了。只是记录一下使用心得,讲得不对的地方欢迎指正。
首先关于如何配置和引入Dagger2这里就不再赘述了。接下来实现一个最顶层的组件,它的生命周期和Applicatoin一样长。

@Singleton
@Component(modules = AppMoudel.class)
public interface AppComponent {
    void inject(TrajectoryApplication application);

     Picasso getPicasso();

    Context context();
}

@Singleton:单例的,此注解标记过的代表着与程序有着一样长的生命周期。
@Component:它是连接@Inject和@Module的桥梁,我理解为将你需要注入的对象和对象的提供者联系起来。无疑modules = AppMoudel.class,这里就是在说对象的提供者。inject(TrajectoryApplication application)这里就是在声明对象的需求者。(如果理解得不对的话,不要打我)
接下来我们看module的实现

@Module
public class AppMoudel {
    private Application application;

    public AppMoudel(Application application) {
        this.application = application;
    }

    @Provides
    @Singleton
    public Application providesApplication() {
        return application;
    }

    @Provides
    @Singleton
    Context provideApplicationContext() {
        return this.application;
    }

    @Provides
    @Singleton
    public Picasso providesPicasso(Context context) {
        return Picasso.with(context);
    }

    @Provides
    @Singleton
    public PreferencesHelper providesSharedPreferences(PreferencesHelper spfUtils) {
        return spfUtils;
    }
}

其中:我现在发现两种注入方式。
1,能够访问到目标类的构造函数,将其构造函数以 @Inject注解。例如这里的PreferencesHelper类

    @Inject
    public PreferencesHelper(Context context) {
        this.context = context;
    }

这种方式就比较方便了,你可以直接在Component将其暴露出来,也可以像上面代码那样通过参数形式注入,还可以自己在Module里自己new出来。

    @Provides
    @Singleton
    public PreferencesHelper providesSharedPreferences() {
        return new PreferencesHelper(provideApplicationContext());
    }

在注解构造函数的情况下,这三种形式均可实现注入,具体使用哪一种就随你高兴了。
2,在无法注解构造函数的情况下,例如某些第三方的轮子,我们无法修改其代码。如实例代码中的Picasso。
这种情况下,就必须先在Module里自己实例化对象,然后必须在Component中将其暴露出来。如实例代码中的Picasso,除了在Module里完成了自己的创建,还必须在AppComponent中将其暴露出去。否则编辑阶段便会报错

最后:@Provides所需要的参数可以由别的@Provides提供。例如这里的providesPicasso(Context context),其中括号中的context由providesApplication()方法提供。
然后看下面一段代码:

public class TrajectoryApplication extends Application {
    private AppComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        initializeInjector();
    }

    private void initializeInjector() {
        appComponent = DaggerAppComponent.builder()
                .appMoudel(new AppMoudel(this))
                .build();
        appComponent.inject(this);
    }

    public AppComponent getAppComponent() {
        return appComponent;
    }
}

编译之后会多出一个类,这个类一般是以Dagger开头就是这里的DaggerAppComponent,然后就是一系列builder();
接下来是自定义注解,这里主要是自定义一个和Activity一样生命周期的组件,自定义的范围注解,作用是允许对象被记录在正确的组件中,当然这些对象的生命周期应该遵循activity的生命周期

@Scope
@Retention(RUNTIME)
public @interface PerActivity {
}

@PerActivity
@Component(dependencies = AppComponent.class, modules = {ActivityMoudel.class, HomeModule.class})
public interface HomeComponent {
    void inject(HomeActivity homeActivity);

    HomePresenter getHomePresenter();
}

通过@PerActivity注解其生命周期跟Activity一样。
最后

@Module
public class HomeModule {
    @Provides
    public HomePresenter providesHome(HomePresenterImpl homePresenter) {
        return homePresenter;
    }
}

注意:这里的注入类型一定要写实际类型,不要写成接口,不要写成接口,不要写成接口
我们的配置基本完成了,最后就是我们的使用,已达到文章开头提到的目的。
看如下代码

public class HomeActivity extends MvpBaseActivity<HomePresenter> implements HomeView {
    @Inject
    PreferencesHelper preferencesHelper;
    @Inject
    Picasso picasso;
    @Inject
    HomePresenter homePresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        Log.i("TAG", preferencesHelper.toString());
        Log.i("TAG", picasso.toString());
    }

    @Override
    protected HomePresenter createPresenter() {
        return homePresenter;
    }

    //由基类调用完成
    @Override
    public void initializeInjector() {
        homeComponent = DaggerHomeComponent.builder()
                .appComponent(getAppComponent())
                .activityMoudel(getActivityMoudel())
                .homeModule(new HomeModule())
                .build();
        homeComponent.inject(this);
    }
}

看看,做过web开发的童鞋,是不是有一种熟悉的味道?通过@Inject修饰的类,直接就被注入进来了。层与层之间再也不用担心耦合问题,依赖的注入和配置独立于组件之外,注入的对象在一个独立、不耦合的地方初始化,这样在改变注入对象时,我们只需要修改对象的实现方法,而不用大改代码库。事实证明Dagger2和MVP真的很配,建议大家使用起来。
下面附上demo下载链接:
https://github.com/qq605088820/dagger2demo.git

扫描二维码关注公众号,回复: 2410747 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_23186653/article/details/51150169