Dagger2使用指北
Dagger2是正方形公司推出的一款依賴注入的框架,第二代由谷歌接手,在Android屆可是大名鼎鼎的難學,我也是反覆看了一遍又一遍才稍微有點頭緒,本文就是Dagger2的使用指北,包括後面如何整合到專案中,也儘量寫下來。
1.引入
implementation 'com.google.dagger:dagger:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
2.Dagger2的作用是什麼呢?
我們來看這樣一個例子,假如此時有一個Apple類,要在MainActivity中使用該類,傳統的方法,是在MainActivity類中new出這個物件,如下:
public class MainActivity extends AppCompatActivity {
//使用
Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
apple = new Apple(20);
Log.i("我是一個蘋果","");
}
}
但是使用Dagger2,就不再需要new出Apple類,直接注入即可。如下:
public class MainActivity extends AppCompatActivity {
//使用
@Inject
Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入
DaggerGangJingComponent.builder().appleModule(new AppleModule(90))
.build().inject(this);
Log.i("我是一個蘋果","");
}
}
那麼我們現在就是需要在專案中使用這個Apple類,怎麼來使用Dagger2來建立呢?有哪些建立方式呢?後文會詳細解釋清楚。
1.最簡單不帶Module的inject方式
由我們自己定義的類,我們可以自由修改的前提下使用這種方式,分為兩種:帶參和不帶參。
建構函式不帶參的類:
- 由類提供:
//第一,將我們需要注入的物件的類的構造引數使用@Inject標註,告訴dagger2它可以例項化這個類;
public class Apple {
@Inject
public Apple() {
}
}
2.由component連線
//第二,編寫Component介面使用@Component進行標註,裡面的void inject()的參數列示要將依賴注入到的目標位置;
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
3.使用Apple
//
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第三,使用android studio的Build選單編譯一下專案,使它自動生成我們編寫的Component所對應的類,生成的類的名字的格式為 "Dagger+我們所定義的Component的名字";
//第四,在需要注入的類中使用@Inject標註要注入的變數;然後呼叫自動生成的Component類的方法create()或builder().build(),然後inject到當前類;在這之後就可以使用這個@Inject標註的變數了。
DaggerAppleComponent.create().inject(this);
Log.i("蘋果",apple+"");
}
}
建構函式帶引數的類,引數為引用型別
如果引數是基本型別呢?
- 假如Apple中帶有一個Kinfe類的引數如下:
public class Apple {
Knife knife;
//Apple的構造方法使用@Inject標註,告訴Dagger2可以例項化這個類
@Inject
public Apple(Knife knife) {
this.knife = knife;
}
}
2.引數Knife的構造方法也需要提供注入,由@Inject標記,告訴Dagger2可以例項化這個類。
public class Knife {
@Inject
public Knife() {
}
}
3.使用component連線二者:類和要注入該類的目標位置。inject的引數就是要把該類注入到的目標位置。
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
4.Bulid一下專案,生成一個DaggerAppleComponent,通過該類使用注入的物件。
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入Apple
DaggerAppleComponent.create().inject(this);
//使用Apple
Log.i("蘋果",apple+","+apple.knife);
}
2.帶Module的Inject方式
在不能更改建構函式的情況下(比如引入第三方類OkHttpClient等),我們無法在建構函式上新增@Inject標記,就只能使用Module來實現類的提供。
構造方法不帶引數
1.假如我們的Apple類是由第三方提供的,我們不可以更改其程式碼。
public class Apple {
Knife knife;
public Apple() {
}
public Knife getKnife() {
return knife;
}
public void setKnife(Knife knife) {
this.knife = knife;
}
}
2.編寫Module類,並且使用@Module標註,在該類中提供我們需要inject的物件,提供該物件的方法使用@Provides標註
@Module
public class AppleModule {
@Provides
public Apple providesApple(){
return new Apple();
}
}
3.在component介面中,使用modules = xxxModule.class連結上一步編寫的Module類。
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
}
4.依然是在目標位置注入該物件,並使用
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.create().inject(this);
Log.i("蘋果",apple+"");
}
}
建構函式帶引數
1.編寫Module類,使用@Module標記,並且在Module的構造方法中傳入引數,引數和物件一樣,都需要寫個方法提供出來。
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
public Apple providesApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
2.component介面寫法同上
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
}
3.build一下,生成DaggerXXXModule類,使用該類的build方法並傳入引數來注入物件。
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("藍色的蘋果"))
.build().inject(this);
Log.i("蘋果",apple+"");
}
}
@Qualifier 自定義註解
現在有這樣的情況,如果一個類,有兩個構造方法,一個帶參,一個不帶參,如果要同時使用帶參和不帶參的物件,那麼怎麼來區分呢?
1. 使用@Named註解進行標記。
使用該型別註解(@Named或者@Qualifier),不能直接在建構函式上標記,否則會報錯誤:
@Qualifier annotations are not allowed on @Inject constructors.
在Module類中,使用@Named註解標記:
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
@Named("normal")
public Apple providesApple(){
return new Apple();
}
@Provides
@Named("named")
public Apple providesNamedApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
2.使用時需要使用@Named進行區分。
public class MainActivity extends AppCompatActivity {
@Inject
@Named("normal")
public Apple apple;
@Inject
@Named("named")
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("紅色")).build()
.inject(this);
Log.i("蘋果",apple+"");
Log.i("蘋果1",apple1+""+apple1.name);
}
}
3.其它建立Component介面的程式碼均相同。
2.使用@Qualifier自定義註解
1.建立一個註解類 命名為Type,並用@Qualifier註解標記,需要指明是執行時註解。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
String value() default "";
}
2.把上一步中的Named全部換成自己定義的Type即可。
在Module中:
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Provides
@Type("normal")
public Apple providesApple(){
return new Apple();
}
@Provides
@Type("named")
public Apple providesNamedApple(){
return new Apple(name);
}
@Provides
public String providesName(){
return name;
}
}
使用時:
public class MainActivity extends AppCompatActivity {
@Inject
@Type("normal")
public Apple apple;
@Inject
@Type("named")
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.builder().appleModule(new AppleModule("紅色")).build()
.inject(this);
Log.i("蘋果",apple+"");
Log.i("蘋果1",apple1+""+apple1.name);
}
}
Singleton 單例
怎樣使用Dagger2建立單例物件呢?
無Module方式
1.在物件類上使用@Singleton標記
@Singleton
public class Apple {
@Inject
public Apple() {
}
}
2.使用@Singleton標記component介面
@Singleton
@Component
public interface AppleComponent {
void inject(MainActivity activity);
}
3.注入並使用Apple物件
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Inject
public Apple apple1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAppleComponent.create().inject(this);
Log.i("蘋果",apple+"");
Log.i("蘋果1",apple1+"");
}
}
列印結果如下:
有Module方式
出現Module類的初衷是物件類不可更改,因此,有Module類時,不需要對物件類進行任何的更改,使用單例也只需要在Module類中進行更改即可。
1.Module類中提供物件的方法上,使用@Singleton標記。
@Module
public class AppleModule {
String name;
public AppleModule(String name) {
this.name = name;
}
@Singleton
@Provides
public Apple providesApple(){
return new Apple();
}
@Provides
public String providesName(){
return name;
}
}
2.其他程式碼相同:包括使用@Singleton標記component介面,注入並使用物件。
@Scope 作用域
在作用域內單例。比如有三個Activity,只在前兩個Activity中實現單例。
1.建立自定義註解,使用@Scope註解標記,並標明是執行時註解。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
2.Module 和 component都是用自定義的@PerActivity進行標記。
Module:
@Module
public class AppleModule {
@Provides
@PerActivity
public Apple providesApple(){
return new Apple();
}
}
Component:
@PerActivity
@Component(modules = AppleModule.class)
public interface AppleComponent {
void inject(MainActivity activity);
void inject(Main2Activity activity);
}
3.光使用註解劃定作用域還是不夠的,還需要建立一個Application,在其中獲取獲取AppleComponent物件。
public class AppleApplication extends Application {
private AppleComponent appleComponent;
@Override
public void onCreate() {
super.onCreate();
// 獲取AppleComponent物件
appleComponent = DaggerAppleComponent.builder().appleModule(new AppleModule())
.build();
}
//提供外界獲取AppleComponent的方法
public AppleComponent getAppleComponent() {
return appleComponent;
}
}
4.在需要使用單例Apple的位置獲取AppleComponent物件,並且注入
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((AppleApplication)getApplication()).getAppleComponent().inject(this);
Log.i("Main 蘋果", "onCreate: "+apple);
findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this,Main2Activity.class));
}
});
}
}
Main2Activity.java
public class Main2Activity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
((AppleApplication)getApplication()).getAppleComponent().inject(this);
Log.i("Main2 蘋果",apple+"");
findViewById(R.id.bn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(Main2Activity.this,Main3Activity.class));
}
});
}
}
列印出的結果如下:
Main 蘋果: onCreate: com.kimliu.daggerdemo3.Apple@5ef1d24
Main2 蘋果: com.kimliu.daggerdemo3.Apple@5ef1d24
可以看到,兩個物件的地址相同。
5.不使用單例的目標位置(Main3Activity),需要使用Apple,重新編寫Module,Component注入使用即可。
Module:
@Module
public class Main3Module {
@Provides
public Apple providesApple(){
return new Apple();
}
}
Component:
@Component(modules = Main3Module.class)
public interface Main3Component {
void inject(Main3Activity activity);
}
//使用:
public class Main3Activity extends AppCompatActivity {
@Inject
public Apple apple;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
DaggerMain3Component.create().inject(this);
Log.i("Main3Activity 蘋果", "onCreate: "+apple);
}
}
本文參考:https://www.jianshu.com/p/22c397354997/
https://www.jianshu.com/p/ea4b89352e9a 感謝?
相關文章
- Dagger2的使用
- UIAppearcance 使用指北UIAPP
- proxychains 使用指北AI
- Protocol Buffer 使用指北Protocol
- curl 使用指北&實戰
- Android-ViewModel 使用指北AndroidView
- 3proxy 使用指北
- 【譯】Dagger2在Android中的使用Android
- laravel-echo前端使用指北Laravel前端
- Performance API不完全使用指北ORMAPI
- tar命令基本、進階使用指北
- Flutter 外掛 webview_flutter 使用指北FlutterWebView
- 強行來一波Dagger2使用介紹
- [python] Python平行計算庫Joblib使用指北Python
- Hement:關於專案中的Dagger2的使用(三)
- 當Dagger2撞上ViewModelView
- Dagger2融合篇(三)
- [python] Python日誌記錄庫loguru使用指北Python
- 聽說你還不會用Dagger2?Dagger2 For Android最佳實踐教程Android
- React Hooks 指北ReactHook
- Dagger2基礎篇(一)
- Dagger2進階篇(二)
- [python] Python非同步程式設計庫asyncio使用指北Python非同步程式設計
- 寫給自己看的在 Vue 下使用 Typescript 指北VueTypeScript
- MVP + Dagger2原始碼體驗MVP原始碼
- [深度學習] 時間序列分析工具TSLiB庫使用指北深度學習
- Flutter路由管理指北Flutter路由
- TCP學習指北TCP
- Electron入門指北
- CICD 入門指北
- SourceGenerator入門指北
- Ansible 學習指北
- NPM實用指北NPM
- 「神兵利器Dagger2 | 掘金技術徵文 」
- [python] 啟發式演算法庫scikit-opt使用指北Python演算法
- ArchLinux Vmware安裝指北Linux
- vscode 外掛配置指北VSCode
- 前端開發 ngrok 指北前端