1. 程式人生 > >Dagger2使用攻略---通過生成的程式碼來理解相關概念

Dagger2使用攻略---通過生成的程式碼來理解相關概念

原文網址:http://blog.csdn.net/qq_17766199/article/details/50606011

Dagger2使用攻略

Dagger 2 是 Square 的 Dagger 分支,是一種依賴注入框架。目前由 Google 接手進行開發,Dagger2是使用程式碼自動生成和手寫程式碼來實現依賴注入。據說在 Dagger 的基礎上效率又提升了13%,並且同樣功能強大。

1.Gradle配置

(1)需要配置apt 外掛:(在project根目錄build.gradle檔案中新增如下程式碼)

dependencies {
        ...
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

(2)新增依賴:(在modulebuild.gradle檔案中新增如下程式碼)

apply plugin: 'com.neenbedankt.android-apt'// 註釋處理

    dependencies {
        ...
        compile 'com.google.dagger:dagger:2.0.2'
        apt 'com.google.dagger:dagger-compiler:2.0.2'
        compile 'org.glassfish:javax.annotation:10.0-b28' // Java標註
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

● 當前最新版本是2.0.2

● 如果在專案中同時用了Butterknife,在Build時會報註釋衝突。 
這裡寫圖片描述

解決方法:(在modulebuild.gradle檔案中新增如下程式碼)

 packagingOptions {
        exclude 'META-INF/services/javax.annotation.processing.Processor'
 }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

(3)最後點選Build-->Make Project就可以開始使用Dagger2了。

2.Dagger2 常用註解

寫了一個簡單的Demo,下面根據Demo進行介紹。Dagger2要理解必須看Dagger 2自動生成的程式碼,Build後代碼在專案-->app-->build-->generated-->source-->apt-->debug

目錄下。

1.Inject

@Inject:在需要依賴的地方使用這個註解,告訴Dagger這個類或者欄位需要依賴注入,這樣Dagger會構造一個這個類例項來滿足依賴。

1.構造器注入:首先舉一個簡單的例子,無參構造方法。

public class Person {
    private String name;
    private int age;

    @Inject
    public Person() {
    }

    public String getName() {
        return "Jack";
    }

    public int getAge() {
        return 15;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這個的侷限性是我們不能給這個類中的多個構造器作@Inject註解。

2.註解成員變數:

接著上面我們要使用這個例項化類。

public class MainActivity extends AppCompatActivity {

    @Inject
    Person mPerson;

    StorageComponent mStorageComponent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mStorageComponent = ((MyApplication)this.getApplication()).getStorageComponent();
        mStorageComponent.inject(this);//注入MainActivity

        Toast.makeText(this,mPerson.getName() + "----" +mPerson.getAge(),Toast.LENGTH_SHORT).show();
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

這裡我們可以檢視生成的程式碼:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final MembersInjector<AppCompatActivity> supertypeInjector;
  private final Provider<Person> mPersonProvider;

  public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) {  

    assert supertypeInjector != null;
    this.supertypeInjector = supertypeInjector;
    assert mPersonProvider != null;
    this.mPersonProvider = mPersonProvider;
  }

  @Override
  public void injectMembers(MainActivity instance) {  
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    supertypeInjector.injectMembers(instance);
    instance.mPerson = mPersonProvider.get();//這裡mPersonProvider替我們例項化了Person
  }

  public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) {  
      return new MainActivity_MembersInjector(supertypeInjector, mPersonProvider);
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

同時我們也可以瞭解到@Inject Person mPerson; 為什麼不能使用private 。上面程式碼中的injectMembers 方法呼叫後面會說到。

3.方法注入

public class LoginActivityPresenter {

    private LoginActivity loginActivity;

    @Inject //構造方法注入
    public LoginActivityPresenter(LoginActivity loginActivity) {
        this.loginActivity = loginActivity;
    }

    @Inject //方法注入
    public void enableWatches(Watches watches) {
        watches.register(this);   
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

如當我們希望傳入類的當前例項(this引用)到被注入的依賴中。方法注入會在構造器呼叫後馬上被呼叫,所以這表示我們可以傳入完全被構造的this。

2.Module

@Module:用來修飾類,表示此類的方法是用來提供依賴的,它告訴Dagger在哪裡可以找到依賴。

@Module
public class StorageModule {

    private final MyApplication application;

    public StorageModule(MyApplication application) {
        this.application = application;
    }

    @Provides
    @Singleton
    SharedPreferences provideSharedPreferences(){
        return PreferenceManager.getDefaultSharedPreferences(application);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

@Provides下面說到,@Singleton 單例,使用@Singleton註解之後,物件只會被初始化一次,之後的每次都會被直接注入相同的物件。@Singleton就是一個內建的作用域。

3.Provides

@Provides:在@Module 中使用,我們定義的方法用這個註解,用於告訴 Dagger 我們需要構造例項並提供依賴。

為什麼要使用@Provides,因為預設情況下,Dagger滿足依賴關係是通過呼叫構造方法得到的例項,比如上面的Person類使用。但是有時因為@Inject的侷限性,我們不能使用@Inject。比如構造方法有多個、三方庫中的類我們不知道他是怎麼實現的等等。例如下面程式碼中的SharedPreferences,我們使用@Provides 返回一個建立好的例項,這樣做也顯得靈活不是嗎?

    @Provides
    @Singleton
    SharedPreferences provideSharedPreferences(){
        return PreferenceManager.getDefaultSharedPreferences(application);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

注意:

● 按照習慣 @Providers方法都會用provide作為字首,@Module類都用Module作為字尾。

● 如果@Provides方法有引數,這個引數也要保證能夠被Dagger得到(例如通過其他的@Provides方法或者@Inject註解的構造方法。)

4.Component

@Component: 是@Inject@Module的橋樑,需要列出所有的@Modules以組成該元件。

@Singleton
@Component(modules = {
        StorageModule.class ,
        ScheduleModule.class
})
public interface StorageComponent {

    Storage execute();
    void inject(MainActivity mMainActivity);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Dagger會按照上面介面生成一個實現類,生成類以Dagger為字首,提供builder()來生成例項。呼叫方法:(因為是單例,所以這裡放到了MyApplication)

public class MyApplication extends Application {

    private StorageComponent component;

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

        component = DaggerStorageComponent
                .builder()//呼叫構建類
                .storageModule(new StorageModule(this)) //傳入Module
                .build();//生成例項

    }

    public StorageComponent getStorageComponent() {
        return component;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

MainActivity程式碼:

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.button1)
    Button mButton1;

    @Bind(R.id.button2)
    Button mButton2;

    @Inject
    SharedPreferences mPreferences;//全域性的SharedPreferences

    @Inject
    Person mPerson;

    StorageCo