Android Dagger2依赖注入

简介: Dagger2项目主页使用依赖 annotationProcessor 'com.google.dagger:dagger-compiler:2.

Dagger2项目主页

使用依赖

    annotationProcessor 'com.google.dagger:dagger-compiler:2.2'
    compile 'com.google.dagger:dagger:2.2'
    provided 'javax.annotation:jsr250-api:1.0'

1. 先创建最基本的四个类

img_11e025805d51977ccf934c24ea9c2155.png
图1.png

代码:

/**
 * @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单元测试:


img_85ecd8b7790b27c44463c25e9ae43061.png
图2.png
/**
 * @author mazaiting
 * @date 2018/1/9
 */
public class CarTest {

    @Test
    public void testCar(){
        new Car();
    }
}
  • 使用Dagger2之后,先要创建一个CarModule类,再创建一个CarComponent接口或者抽象类,接下来Ctrl+F9进行编译,如果编译成功,则会生成DaggerCarComponent类(生成的Dagger开头,并且后面为Component组件的接口名/抽象类名),这个类提供注册Module类和注入当前类。


    img_034504c7d83721f9693676ef35b7d640.png
    图3.png
/**
 * @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单元测试,打印结果


img_6616a87f2d3c390d4f8e6e5cfa3729a4.png
图4.png

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单元测试,发现它默认调用的是无参数的构造方法


img_bcd132876e4e85be0ed246b77bb10c78.png
图5.png

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单元测试


img_95ed6976f6a97fa4f315b78cbf0f6d0e.png
图6.png

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();
    }

单元测试打印结果:


img_f1a43e063f8a28a3b90406db2a408c4f.png
图7.png

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>
目录
相关文章
|
8月前
|
Java 数据库 Android开发
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(三)
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(三)
101 0
|
8月前
|
Android开发
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(四)
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(四)
72 0
|
8月前
|
Android开发 容器
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(二)上
使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(二)
60 0
|
测试技术 数据库 Android开发
Android Jetpack 浅析Hilt依赖注入
首先,某个类的成员变量称为依赖,如若此变量想要实例化引用其类的方法,可以通过构造函数传参或者通过某个方法获取对象,此等通过外部方法获取对象实例的称为依赖注入;而依赖注入又可以简单分为`手动注入`和`自动注入`两种方式;`Hilt`就是基于Dagger进行`场景化优化`的一个依赖注入库,Hilt是Google专门为Android平台打造的一个依赖注入库,在使用上极大程度进行啦简化(与dagger相比)
312 1
Android | 依赖注入与 Dagger2 框架【@Deprecated】
Android | 依赖注入与 Dagger2 框架【@Deprecated】
170 0
Android | 依赖注入与 Dagger2 框架【@Deprecated】
|
前端开发 Android开发 开发者
Dagger Hilt - Android官方推荐的依赖注入框架
Dagger Hilt 帮助 Android 项目实现依赖注入
518 0
|
Java Android开发 开发者
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 创建 事件监听器 对应的 动态代理 | 动态代理的数据准备 | 创建调用处理程序 | 创建动态代理实例对象 )
155 0
|
Android开发
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )
219 0
|
Android开发
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取 Activity 中的所有方法 | 获取方法上的注解 | 获取注解上的注解 | 通过注解属性获取事件信息 )
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取 Activity 中的所有方法 | 获取方法上的注解 | 获取注解上的注解 | 通过注解属性获取事件信息 )
121 0
|
Android开发
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入代码示例 )(二)
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入代码示例 )(二)
191 0
【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入代码示例 )(二)