依赖注入--Dagger2

一.什么是依赖注入,首先我认为是一种编程思想
简单来说,依赖注入就是为了控制反转和解耦的
当两个类或多个类 组合使用时,不可避免的会发生以下情况:
public class MovieLister {
private MovieFinder finder;

public MovieLister() {
finder = new MovieFinderImpl();
}
public Movie[] moviesDirectedBy(String arg) {
List allMovies = finder.findAll();
for (Iterator it = allMovies.iterator(); it.hasNext();) {
Movie movie = (Movie) it.next();
if (!movie.getDirector().equals(arg)) it.remove();
}
return (Movie[]) allMovies.toArray(new Movie[allMovies.size()]);
}
...
}


public interface MovieFinder {
List findAll () ;
}

可见 MovieFinder 接口 在 MovieLister类的构造器中实例化 这样我们就可以说 MovieFinder 接口是依赖于 MovieLister的. 这样增加了代码的耦合性,非常的不好

由此引入了依赖注入这种设计思想,关键在于达到相同的需求还要降低耦合度

在不使用框架的情况下 依赖注入有以下几种常见的方式
1.通过构造函数注入(Contructor Injection)

这是我认为的最简单的依赖注入方式,我们修改一下上面代码中MovieList的构造函数,使得MovieFinderImpl的实现在MovieLister类之外创建。
这样,MovieLister就只依赖于我们定义的MovieFinder接口,而不依赖于MovieFinder的实现了。


public class MovieLister {
private MovieFinder finder;

public MovieLister(MovieFinder finder) {
this.finder = finder;
}
...
}

2.通过setter注入

类似的,我们可以增加一个setter函数来传入创建好的MovieFinder对象,这样同样可以避免在MovieFinder中hard init这个对象。

public class MovieLister {
s...
public void setFinder(MovieFinder finder) {
this.finder = finder;
}
}

3.接口注入

接口注入使用接口来提供setter方法,其实现方式如下。
首先要创建一个注入使用的接口。

public interface InjectFinder {
void injectFinder(MovieFinder finder);
}

之后,我们让MovieLister实现这个接口。

class MovieLister implements InjectFinder {
...
public void injectFinder(MovieFinder finder) {
this.finder = finder;
}
...
}

可以看到以上三种方法 MovieFinder 接口不再 在MovieLister 类里实例化了
MovieLister 类里只是持有MovieFinder 的引用,大大的降低了代码的耦合性

二.Dagger2

Dagger2是一种依赖注入的框架
1. Dagger2是什么?
Dagger2在Github主页上的自我介绍是:“A fast dependency injector for Android and Java“(一个提供给Android和Java使用的快速依赖注射器。)

2. 使用依赖注入的最大好处是什么?
没错,就是模块间解耦! 就拿当前Android非常流行的开发模式MVP来说,使用Dagger2可以将MVP中的V 层与P层进一步解耦,这样便可以提高代码的健壮性和可维护性。

3.Dagger2的用法
3.1. 注解
Dagger2 通过注解来生成代码,定义不同的角色,主要的注解如下:
@Module: Module类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的依赖。
@Provides :在Module中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
@Inject: 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。
@Component :Component从根本上来说就是一个注入器,也可以说是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分。将Module中产生的依赖对象自动注入到需要依赖实例的Container中。
@Scope: Dagger2可以通过自定义注解限定注解作用域,来管理每个对象实例的生命周期。
@Qualifier :当类的类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示。例如:在Android中,我们会需要不同类型的context,所以我们就可以定义 qualifier注解“@perApp”和“@perActivity”,这样当注入一个context的时候,我们就可以告诉 Dagger我们想要哪种类型的context。
3.2 结构
Dagger2要实现一个完整的依赖注入,必不可少的元素有三种:Module,Component,Container。
为了便于理解,其实可以把component想象成针管,module是注射瓶,里面的依赖对象是注入的药水,build方法是插进患者(Container),inject方法的调用是推动活塞。

简单来说:component(理解为注射器) 将Module中的依赖 注入到Container
3. 配置
  • 配置apt插件(在build.gradle(Project:xxx)中添加如下代码)
dependencies { classpath 'com.android.tools.build:gradle:2.1.0' //添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }
  • 添加依赖(在build.gradle(Module:app)中添加如下代码)
apply plugin: 'com.android.application' //添加如下代码,应用apt插件 apply plugin: 'com.neenbedankt.android-apt' ... dependencies { ... compile 'com.google.dagger:dagger:2.4' apt 'com.google.dagger:dagger-compiler:2.4' //java注解 compile 'org.glassfish:javax.annotation:10.0-b28' ... }

下面举一个简单的例子:

4. 简单的例子

4.1最简单的方式
实现Module
继续上面的例子:
@Module // 注明本类是Module public class MyModule { @Provides // 注明该方法是用来提供依赖对象的方法 public B provideB (){ return new B (); } }
实现Component
@Component ( modules ={ MyModule . class }) // 指明Component查找Module的位置 public interface MyComponent { // 必须定义为接口,Dagger2框架将自动生成Component的实现类,对应的类名是Dagger×××××,这里对应的实现类是DaggerMyComponent void inject ( A a ); // 注入到A(Container)的方法,方法名一般使用inject }
实现Container
A就是可以被注入依赖关系的容器。
public A { @Inject //标记b将被注入 B b ; // 成员变量要求是包级可见,也就是说@Inject不可以标记为private类型。 public void init (){ DaggerMyComponent . create (). inject ( this ); // 将实现类注入 } }
当调用A的init()方法时, b将会自动被赋予实现类的对象。

2.当bean 有有参构造器

需要参数的实例化对象
Person 的构造方法发生了变化,需要传入一个 Context ,代码如下:
public class Person { private Context mContext; public Person(Context context){ mContext = context; Log.i( "dagger" , "create" ); }}

这样的话,我们需要修改 MainModule
@Module //提供依赖对象的实例 public class MainModule { private Context mContext; public MainModule(Context context){ mContext = context; } @Provides Context providesContext(){ // 提供上下文对象 return mContext; } @Provides // 关键字,标明该方法提供依赖对象 @Singleton Person providerPerson(Context context){ return new Person(context); }}
  • 修改providerPerson方法,传入Context对象。
  • 添加providesContext(),用以提供Context对象。
看一下使用
// 构造桥梁对象 MainComponent component = DaggerMainComponent.builder().mainModule( new MainModule( this )).build(); //注入 component.inject( this );




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin 依赖注入是一种设计模式,它可以帮助我们解耦代码并提高可测试性。Kotlin 中常用的依赖注入框架有 Koin 和 Dagger2。 Koin 是一个轻量级的依赖注入框架,它使用 Kotlin 语言特性来实现依赖注入。Koin 简单易用,不需要编写任何代码,只需要定义模块和依赖关系即可。以下是一个使用 Koin 进行依赖注入的示例: ```kotlin // 定义一个模块 val appModule = module { single { NetworkService() } factory { UserRepository(get()) } viewModel { MainViewModel(get()) } } // 在 Application 中初始化 Koin class MyApp : Application() { override fun onCreate() { super.onCreate() startKoin { androidContext(this@MyApp) modules(appModule) } } } // 在 Activity 中使用依赖注入 class MainActivity : AppCompatActivity() { private val viewModel: MainViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 使用 viewModel viewModel.doSomething() } } ``` Dagger2 是一个功能强大的依赖注入框架,它可以在编译时生成依赖注入代码,提高运行时的性能。Dagger2 的使用比 Koin 更为复杂,需要定义组件、模块、依赖关系等。以下是一个使用 Dagger2 进行依赖注入的示例: ```kotlin // 定义一个模块 @Module class AppModule { @Provides fun provideNetworkService(): NetworkService { return NetworkService() } @Provides fun provideUserRepository(networkService: NetworkService): UserRepository { return UserRepository(networkService) } } // 定义一个组件 @Component(modules = [AppModule::class]) interface AppComponent { fun inject(activity: MainActivity) } // 在 Application 中初始化 Dagger2 class MyApp : Application() { lateinit var appComponent: AppComponent override fun onCreate() { super.onCreate() appComponent = DaggerAppComponent.builder() .build() } } // 在 Activity 中使用依赖注入 class MainActivity : AppCompatActivity() { @Inject lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 注入依赖 (application as MyApp).appComponent.inject(this) // 使用 viewModel viewModel.doSomething() } } ``` 总体来说,Koin 适合小型项目和快速原型开发,而 Dagger2 则适合大型项目和需要高性能的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值