Dagger2项目主页
使用依赖
annotationProcessor 'com.google.dagger:dagger-compiler:2.2'
compile 'com.google.dagger:dagger:2.2'
provided 'javax.annotation:jsr250-api:1.0'
1. 先创建最基本的四个类
代码:
/**
* @author mazaiting
* @date 2018/1/8
*/
public class Config {
public static final String TAG = "Config";
}
/**
* 引擎
* @author mazaiting
* @date 2018/1/8
*/
public class Engine {
public Engine(){
Log.e(Config.TAG, "Engine: new Engine()");
}
}
/**
* *
* @author mazaiting
* @date 2018/1/8
*/
public class Wheel {
public Wheel(){
Log.e(Config.TAG, "Wheel: new Wheel()");
}
}
/**
* 车座
* @author mazaiting
* @date 2018/1/8
*/
public class Seat {
public Seat(){
Log.e(Config.TAG, "Seat: new Seat()");
}
}
2. Dagger2是一个依赖注入的框架。
- 之前我们写代码如下, Car类依赖于其他三个类,并且在构造方法中创建其他三个类的对象,这样,Car类在构造方法中对其他三个类的耦合度较高
/**
* 车
* @author mazaiting
* @date 2018/1/8
*/
public class Car {
private Engine mEngine;
private Seat mSeat;
private Wheel mWheel;
public Car() {
mEngine = new Engine();
mSeat = new Seat();
mWheel = new Wheel();
Log.e(Config.TAG, "Car: new Car()");
}
}
执行Android单元测试:
/**
* @author mazaiting
* @date 2018/1/9
*/
public class CarTest {
@Test
public void testCar(){
new Car();
}
}
-
使用Dagger2之后,先要创建一个CarModule类,再创建一个CarComponent接口或者抽象类,接下来Ctrl+F9进行编译,如果编译成功,则会生成DaggerCarComponent类(生成的Dagger开头,并且后面为Component组件的接口名/抽象类名),这个类提供注册Module类和注入当前类。
/**
* @Module用来管理并提供依赖
* @Provides用来提供依赖
* @author mazaiting
* @date 2018/1/8
*/
@Module
public class CarModule {
@Provides
public Engine provideEngine(){
return new Engine();
}
@Provides
public Seat provideSeat(){
return new Seat();
}
@Provides
public Wheel provideWheel(){
return new Wheel();
}
}
/**
* 组件
* @author mazaiting
* @date 2018/1/8
*/
@Component(modules = CarModule.class)
public interface CarComponent {
/**
* 实现注入
* @param car
*/
void inject(Car car);
}
/**
* 车
* @author mazaiting
* @date 2018/1/8
*/
public class Car {
@Inject Engine mEngine;
@Inject Seat mSeat;
@Inject Wheel mWheel;
public Car() {
DaggerCarComponent
.builder()
.carModule(new CarModule())
.build()
.inject(this);
Log.e(Config.TAG, "Car: new Car()");
}
}
// Component抽象类实现法
/**
* @author mazaiting
* @date 2018/1/9
*/
@Component(modules = CarModule.class)
public abstract class CarComponent {
/**
* @param car
*/
public abstract void inject(Car car);
}
执行上一步的Android单元测试,打印结果
3. 以上用到的注解解释
- @Module 标注用来管理并提供依赖。里面定义一些用@Provides注解的以provide开头的方法,这些方法就是所提供的依赖,Dagger2会在该类中寻找实例化某个类所需要的依赖。
- @Provides 标注用来提供依赖
- @Component 标注接口或者抽象类,用来将@Inject和@Module联系起来的桥梁,从@Module中获取依赖并将依赖注入给@Inject。参数module,用来指定用注解@Module标识的类。
- @Inject 标注目标类中所依赖的其他类,标注所依赖的其他类的构造函数
4. 多个构造方法
1). 给Engine类添加一个构造方法
/**
* 引擎
* @author mazaiting
* @date 2018/1/8
*/
public class Engine {
public Engine(){
Log.e(Config.TAG, "Engine: new Engine()");
}
public Engine(String string){
Log.e(Config.TAG, "Engine: " + string);
}
}
2). 此时运行之前的Android单元测试,发现它默认调用的是无参数的构造方法
3). 但此时我们就想让它去调用含一个参数的构造方法,我们可以这么做
I>. 自定义一个注解,必须使用@Qualifier修饰器
/**
* 标识引擎的颜色
* @author mazaiting
* @date 2018/1/9
*/
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface EngineString {
String string() default "white";
}
II>. 在CarModule中添加一个提供Engine的方法,并使用刚刚自定义的注解
@Module
public class CarModule {
@Provides
public Engine provideEngine(){
return new Engine();
}
// ... 省略其他的方法
@EngineString(string = "black")
@Provides
public Engine provideStringEngine(){
return new Engine("black");
}
}
III>. 在Car类中,声明Engine的使用,同样也使用刚刚自定义的注解标识
/**
* 车
* @author mazaiting
* @date 2018/1/8
*/
public class Car {
@EngineString(string = "black")
@Inject Engine mEngine;
@Inject Seat mSeat;
@Inject Wheel mWheel;
public Car() {
DaggerCarComponent
.builder()
.carModule(new CarModule())
.build()
.inject(this);
Log.e(Config.TAG, "Car: new Car()");
}
}
IV>. 使用之前的Android单元测试
5. @Named注解
@Named 是基于@Qualifier的注解,不过只能传递字符串
@Qualifier 包括但不限于字符串,如枚举等。
6. Lazy<T>懒加载数据
public class Car {
@EngineString(string = "black")
@Inject Engine mEngineBlack;
@Named(value = "10")
@Inject Engine mEngine;
@Inject Seat mSeat;
@Inject
Lazy<Wheel> mWheelLazy;
public Car() {
DaggerCarComponent
.builder()
.carModule(new CarModule())
.build()
.inject(this);
Log.e(Config.TAG, "Car: new Car()");
}
// 使用懒加载的变量
public void useWheel(){
mWheelLazy.get();
}
}
新建Android 单元测试
@Test
public void testCar1(){
final Car car = new Car();
new Thread(new Runnable() {
@Override
public void run() {
Log.e("tag", "useWheel" + Thread.currentThread());
car.useWheel();
}
}).start();
}
单元测试打印结果:
7. @Singleton 当前提供的对象将是单例模式 ,一般配合@Provides一起出现。
8. 使用示例
AppModule.java
/**
* @author mazaiting
* @date 2018/1/9
*/
@Module
public class AppModule {
Application mApplication;
public AppModule(Application application){
this.mApplication = application;
}
@Provides
@Singleton
Application provideApplication(){
return this.mApplication;
}
}
NetModule.java
/**
* @author mazaiting
* @date 2018/1/9
*/
@Module
public class NetModule {
String mBaseUrl;
// Constructor needs one parameter to instantiate.
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
// Dagger will only look for methods annotated with @Provides
@Provides
@Singleton
// Application reference must come from AppModule.class
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
@Provides
@Singleton
Cache provideOkHttpCache(Application application) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(application.getCacheDir(), cacheSize);
return cache;
}
@Provides
@Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
@Provides @Named("cached")
@Singleton
OkHttpClient provideOkHttpClientCache(Cache cache) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cache(cache);
return builder.build();
}
@Provides @Named("non_cached")
@Singleton
OkHttpClient provideOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
return builder.build();
}
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(mBaseUrl)
.client(okHttpClient)
.build();
return retrofit;
}
}
NetComponent.java
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
/**
* @param activity
*/
void inject(MainActivity activity);
}
完成前三个类之后编译,生成DaggerNetComponent.java.
MyApp.java
public class MyApp extends Application {
private NetComponent mNetComponent;
@Override
public void onCreate() {
super.onCreate();
mNetComponent =
DaggerNetComponent
.builder()
.appModule(new AppModule(this))
.netModule(new NetModule("http://www.baidu.com/"))
.build();
}
public NetComponent getNetComponent(){
return mNetComponent;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Inject @Named("cached")
OkHttpClient mClient;
@Inject @Named("non_cached")
OkHttpClient mOkHttpClient;
@Inject
SharedPreferences mSharedPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// new Car();
((MyApp)getApplication()).getNetComponent().inject(this);
}
// 写数据
public void write(View view){
mSharedPreferences.edit().putString("key", "value").apply();
}
// 读数据
public void read(View view){
Toast.makeText(this, mSharedPreferences.getString("key", "string"), Toast.LENGTH_SHORT).show();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.mazaiting.dagger2test.MainActivity">
<Button
android:onClick="write"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="write"/>
<Button
android:onClick="read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="read"/>
</LinearLayout>