都在说dagger2,我也来一波dagger2

最近重装了一下系统,笔记忘记保存,全部没了,以后比较难一点的还是写在网上吧。

最近几个月逛论坛不断看到有人说Retrofit、RxJava、dagger2什么的,好像很高大上的样子,刚好最近放假,准备年后再去找实习,所以有空就先来学习一波。

这篇文章主要还是记录一下dagger2是干什么的,怎么用。记得以前刚学android的时候,由于以前学过j2ee,所以对spring框架比较有好感,一度也搜索过android有没有相关的依赖注入框架,不过没找到。好了,进入正题。

参考文章:Dagger ‡ A fast dependency injector for Android and Java.  
     Dependency Injection with Dagger 2


注意:以下所有内容,均由上面两篇与我自己的理解的组合文字,我写这篇博客,肯定不是照着一字一字的翻译过来,那样的话以后我看自己的博客,可能也看不懂了,又得重新去理解,官方的文字总归没有自己的话容易理解。

dagger2是什么

dagger2是android上的一个依赖注入框架,什么是依赖注入框架呢?就是代码不是每次要用的时候都去new new new,这样太low,我们要做到的是,可复用。即,我们只需要定义一个变量,然后加一个注解,容器便自动为这个变量进行初始化,是不是非常方便?(已经在开始我的小白文了)      

@Inject
UserService userService;

dagger2可以干什么

1.使用dagger2可以避免写大量同样的模板代码,这样可以把你的精力放在你感兴趣的事情上面。
2.使用dagger2方便测试,例如你不用只是为了修改一个bll而修改大量的代码。(个人认为这得配合面向接口编程才能达到的效果)
3.使用dagger2使得代码重用变得非常容易,你可以只创建一次,然后在需要的地方进行注入即可。
4.你可以非常方便的管理对象的生命周期。

为什么选择dagger2

dagger2是通过自动生成一些用户以前需要手写的代码来确保依赖注入是简单以及高性能的。说这么多没用,我还是贴代码举个例子吧。这里我就贴上面两篇博客的例子了。例如,当你需要发送一个网络请求的时候,你可能需要这么做。
OkHttpClient client = new OkHttpClient();

// Enable caching for OkHttp
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(getApplication().getCacheDir(), cacheSize);
client.setCache(cache);

// Used for caching authentication tokens
SharedPreferences sharedPrefeences = PreferenceManager.getDefaultSharedPreferences(this);

// Instantiate Gson
Gson gson = new GsonBuilder().create();
GsonConverterFactory converterFactory = GsonConverterFactory.create(Gson);

// Build Retrofit
Retrofit retrofit = new Retrofit.Builder()
                                .baseUrl("https://api.github.com")
                                .addConverterFactory(converterFactory)
                                .client(client)  // custom client
                                .build();

你每次请求都要这么写吗?累吧,那么依赖注入可以怎么做呢。
@Inject OkHttpClient mOkHttpClient;

是不是方便了很多?当然有的人说你可以直接封装写成静态方法然后调用啊,搞什么DI(依赖注入),装什么逼。额。。我觉得好像是这么个道理,知道的人希望不吝赐教。目前我自己的理解就是,通过DI可以把这些可重用的类圈养起来,方便管理,不错之处望指出。
如果你还是不想用dagger2,我只能说,谷歌出品,必属精品(手动斜眼笑)  <0 <0

dagger2怎么用

因为我个人用的是android studio,所以eclipse用户配置方法请自行搜索。as用户的话,在你的app/build.gradle 中添加
dependencies {
    compile 'com.google.dagger:dagger:2.0'
    provided 'com.google.dagger:dagger-compiler:2.0'
    provided 'org.glassfish:javax.annotation:10.0-b28'
}
然后在你项目的build.gradle中添加
dependencies {
     // other classpath definitions here
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 }

最后,在你的app/build.gradle中添加
// add after applying plugin: 'com.android.application'  
apply plugin: 'com.neenbedankt.android-apt'

这样环境就搭好了,as还是挺方便的,然后我们就开始使用dagger2吧。接下来我又要开始我的大白话理解啦。这里我说一下我下面这些代码的目的,很简单,就是声明一个DogService,这个Service里面就一个吠的方法,超级简单。我的目的就是在MainActivity中不使用new的方式,而是使用DI的方式来使用这个DogService。
public class DogService
{
	public void bark()
	{
		Log.e("tag", "wang! wang! wang");
	}
}

创建module

我对module在dagger2中的理解就是,module负责提供类的实例。
@Module
public class AppModule
{

	@Singleton
	@Provides
	DogService providesDogService()
	{
		return new DogService();
	}


}


创建
一个module的步骤:
1.在类的上方添加注解 @Module
2.添加一个提供类实例的方法,这里是provideDogService()  (e.g 官方建议是:@module注解类的命名是以module为后缀,@Provides注解的方法是以provides为前缀,不过我在其他博客中看到,这并不是硬性规定,不过还是照着官方的来吧)。注意这里这个方法,返回值类型即代表它可以注入什么类型的字段。
3.添加注解,这里@Provides表明这个方法向外提供实例,@Singleton表明这个类是单例的,即,无论你在哪个地方注入这个实例,都将是同一个对象。


有了实例提供者之后我们就可以开始注入了吗?答案当然是不可以啦。试想一下,你在MainActivity中给字段加上注解,系统是如何寻找到这个字段的实例的呢?
        @Inject
	DogService mDogService;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		InjectorClass.inject(this);
		mDogService.bark();
	}

首先,肯定得把需要注入的当前activity传递进去,传递到哪?传递到InjectorClass,InjectorClass是什么呢?那就要引出另外一个东西了,Component,Component给我的理解就是负责为类的实例以及需要DI的地方搭一座桥梁,具体怎么实现,看代码!

创建Component接口

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent
{

	void inject(MainActivity mainActivity);
}
创建component的步骤:
1.为接口,注意是接口添加@Component的注解,并将其与AppModule关联起来,前面说过,component相当于一座桥,所以肯定得有上面定义的AppModule的信息啦。
2.提供一个inject方法。负责持有有字段需要DI的类的实例,这里是MainActivity。这里有一点要注意,就是inject方法的参数,你的activity名叫什么,你的变量类型就得是什么,绝对不能写成如下形式。原因?我不知道(掩面逃跑ヽ(≧Д≦)ノ)
void inject(Activity activity);
这样,一个简单的Component就创建好了,通过inject方法以及@component注解里的modules字段,将实例以及需要DI的字段关联起来。

说了这么多,只是把关联的通道打通了而已啊,关键在哪创建这些注入的实例呢?记得前面配置环境那个吗?
// add after applying plugin: 'com.android.application'  
apply plugin: 'com.neenbedankt.android-apt'

如果配置都正确的话,系统会为有@component注解的接口生成一个类,以Dagger为前缀,这里我生成的就是DaggerAppComponent了。嗯,有了这个类,我们还要去构建他。如何构建呢,在哪呢,这里我要小小说一下。因为依赖注入会为我们自动实例化类,这样可能会常驻在内存中,浪费内存,所以有些东西并不是整个应用中都要用到,他可能随着activity的销毁而销毁,这里我不过多说了。
那么像业务逻辑层service这种东西,肯定是整个应用中都存在了,那么肯定要跟着应用一起生一起死啊,所以我们可以把创建Component这件事写在我们的自定义Application中了,代码如下。
public class MyApp extends Application
{
	private AppComponent mAppComponent;

	@Override
	public void onCreate()
	{
		super.onCreate();
		mAppComponent = DaggerAppComponent.builder()
				.appModule(new AppModule())
				.build();
	}

	public AppComponent getAppComponent()
	{
		return mAppComponent;
	}
}

很简单,就是在onCreate方法中构建Component,注意第二个方法appModule(),这个方法是自动生成的,即你在component接口的@component中的modules中关联了什么module,方法名就叫什么。比如我还关联了个sbModule,那么这个自动生成的类将也会有个sbModule方法。然后我们要做的是,就是new我们的module,然后作为参数传递进去就可以了。
如果module有一个空的构造方法,也可以简写成这样。
private AppComponent mAppComponent;

	@Override
	public void onCreate()
	{
		super.onCreate();
//		mAppComponent = DaggerAppComponent.builder()
//				.appModule(new AppModule())
//				.build();
		mAppComponent=DaggerAppComponent.create();
	}

	public AppComponent getAppComponent()
	{
		return mAppComponent;
	}

别忘了在AndroidManifest.xml中改成自己的applicaiton。

MainActivity的最终代码是这样。
@Inject
	DogService mDogService;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		((MyApp)getApplication()).getAppComponent().inject(this);
		mDogService.bark();
	}


不用解释了吧。这里得到的getAppComponent()得到的就是系统根据我们定义的Component自动生成的类的实例。也就是上文提到的InjectorClass。

限于篇幅,我就不继续深入了,大家想继续深入了解可以去我上面贴的两篇文章看看。
为了避免引起误会,我有几点必须说明一下:
1.component中的inject方法不是一定要提供的,有其他方法。
2.构造方法同样可以使用@inject
4.刚才吃饭的时候想到的,现在想不起来了,囧~。以后再填坑。

总结

首先,我在捋一遍思路。
1.我们必须定义一个module类,用于提供实例。
2.我们需要定义一个component接口,接口中需要提供inject方法,参数名为你需要注入的Activity的类名,不能是Activity。通过注解里的module字段,将component与module相关联。
3.根据实例的生命周期,我们选择把创建component创建在application中或者activity中。
4,.得到component实例,调用inject方法进行注入。

然后,我小小的猜测一下dagger2的工作流程,首先在某个类中,如果有需要注入的字段,那么系统首先得确定要通过哪座桥找到module,所以需要找到InjectorClass.inject找到对应的component。找到componet之后,系统就会根据与component关联的module是否有你需要注入的字段的类型。
嗯,大体就是这样,我猜的。
最后,我并没有在实际项目中使用过dagger2,我这几天正在学习Retrofit、RxJava、Dagger2,学习完后我准备用这三个来做一个应用。
我目前也仍在在学习这个框架,如果有哪里写的错了,欢迎指出。

End!~~


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值