dagger2的配置及基本使用(一)
一、配置:
1.1 在Project的gradle指令碼中配置
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
1.2在Module的gradle指令碼中配置
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
apt 'com.google.dagger:dagger-compiler:2.11'
compile 'com.google.dagger:dagger:2.11'
}
二、程式碼實現
2.1、使用@Inject和@Component實現依賴注入
2.1.1: 在實體類的構造方法中標註@Injecct,表示其提供依賴,程式碼如下:
package testdagger.com.xn.testdagger2.modle;
import android.util.Log;
import javax.inject.Inject;
/**
* Created by 賀謀昌 on 2017/8/1.
*/
public class Watch {
@Inject
public Watch() {
}
public void work() {
Log.e("Watch", "Dagger2 watch is work");
}
}
2.1.2:建立注入器,即提供依賴和目標類之前的橋樑,是一個用@Conponent標註的介面
程式碼如下:
package testdagger.com.xn.testdagger2.component;
import dagger.Component;
import testdagger.com.xn.testdagger2.MainActivity;
/**
* Created by 賀謀昌 on 2017/8/1.
*/
@Component
public interface MainActivityComponent {
void inject(MainActivity activity);
}
其建立的方法中傳入的引數為目標類的實體
2.1.3
在目標類中進行注入,並標註依賴注入的實體類
public class MainActivity extends Activity {
@BindView(R.id.btn)
Button btn;
@Inject
Watch watch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
DaggerMainActivityComponent.create().inject(this);
}
@OnClick(R.id.btn)
public void onViewClicked() {
watch.work();
}
}
DaggerMainActivityComponent這個類是在component類完成之後進行reBuild後自動生成的類。
2.2、使用@Module和@Provides提供依賴
如果程式碼中使用了第三方的類庫,那麼目標類所需的依賴是無法進行標註的,因為無法更改實體類的原始碼,比如一個jar包,這時我們用@Module和@Provides提供依賴。
2.2.1、新建一個標註@Module的類,並通過標註@Provides的方法返回實體類的物件,程式碼如下:
/**
* Created by 賀謀昌 on 2017/8/1.
*/
@Module
public class GsonModule {
@Provides
public Gson getGson() {
return new Gson();
}
}
2.2.2、使用已經建立的component來管理Module,只要在類名處標註上管理的是哪個Module即可,程式碼如下:
**
* Created by 賀謀昌 on 2017/8/1.
*/
@Component(modules = GsonModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
2.2.3、在目標類中注入,並標註要使用的實體類,程式碼如下:
public class MainActivity extends Activity {
@BindView(R.id.btn)
Button btn;
@Inject
Watch watch;
@Inject
Gson gson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
DaggerMainActivityComponent.create().inject(this);
}
@OnClick(R.id.btn)
public void onViewClicked() {
watch.work();
JSONObject object = new JSONObject();
try {
object.put("name", "賀賀");
object.put("age", 24);
Man man = gson.fromJson(object.toString(), Man.class);
Log.e("MainActivity", man.getName());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
2.3、如果要注入的物件是抽象的則不能用@Inject來提供依賴,這時要用@Module,案例如下:
Engine是一個抽象類
public abstract class Engine {
public abstract String work();
}
MyEngine是Engine的子類
public class MyEngine extends Engine {
@Override
public String work() {
return "MyEngine is working";
}
}
Car持有Engine的物件
public class Car {
Engine engine;
@Inject
public Car(Engine engine) {
this.engine = engine;
}
public String run() {
return engine.work();
}
}
2.3.1、在component中提供一個方法,給Engine提供例項
@Module
public class GsonModule {
@Provides
public Engine getEngine() {
return new MyEngine();
}
}
2.3.2在MainActivity中注入
@Inject
Car car;
...
DaggerMainActivityComponent.create().inject(this);
....
Log.e("MainActivity", car.run() );
2.4、@Name和Qualifier的基本使用
如果@Inject標註的多個構造或是@Provides標註的方法返回的是同一種類型的值,那麼程式就不知道使用哪一個來提供依賴,這時就會報錯,我們就可以使用@Qualifier來標註我們要使用的是哪一個,@Name是@Qualifier的一種實現。案例如下:
如果Engine的子類有兩個,除了MyEngine之外還有HerEngine,在Module中返回的Engine的例項的方法中,有兩個方法,一個返回MyEngine一個返回HerEngine,這時我們就要標註好哪個方法返回哪個例項,並且目標類需要哪個例項,可以用@name(字串)也可以自定義Qualifier,示例程式碼如下:
//首先定義兩個自定義的Qualifier
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface My {
}
....
....
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Her {
}
....
//在Module中標註好,哪個方法對應的哪個類的例項
@Provides
@My
public Engine getEngine() {
return new MyEngine();
}
@Provides
@Her
public Engine getHerEngine() {
return new HerEngine();
}
// 標註好目標類需要哪個例項
public class Car {
Engine engine;
@Inject
public Car(@Her Engine engine) {
this.engine = engine;
}
public String run() {
return engine.work();
}
}
使用@Name來標註則更為簡單
“`
@Provides
@Named(“My”)
public Engine getEngine() {
return new MyEngine();
}
@Provides
@Named("Her")
public Engine getHerEngine() {
return new HerEngine();
}
//在需要依賴的類中同樣使用@Name標註好
public class Car {
Engine engine;
@Inject
public Car(@Named("Her") Engine engine) {
this.engine = engine;
}
public String run() {
return engine.work();
}
}
2.5、Dagger2實現單例模式
2.5.1、實現區域性單例
在提供依賴的地方標註@Singleton
@Singleton
@Provides
public Gson getGson() {
return new Gson();
}
在Module中標註@Singleton
@Singleton
@Component(modules = GsonModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
//這樣就完成了區域性單例
2.5.2、使用@Scope實現全域性單例模式
其實@Singleton是被@Scope標註的註解,@Scope標註實際上就是用來實現區域性單例的,它的本質就是註解的註解,只要在想要實現某個類是單例模式,只需要在其提供依賴的地方標註被@Scope標註的註解,然後在其component中標註被@Scope標註的註解,上述@Singleton就是做了這樣的操作。還有一個要注意的點就是component會每注入一次就例項化一次,所以我們只要讓Component成為單例,就可以實現全域性單例了。下面開始正式的實現:
新建一個被@Scope標註的註解
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
首先在提供依賴處標註剛定義的註解
@Module
public class GsonModule {
@ApplicationScope
@Provides
public Gson getGson() {
return new Gson();
}
然後在提供依賴處和component處標註此註解
@ApplicationScope
@Component(modules = GsonModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
void inject(SecondActivity activity);
}
新建一個Application在onCreate中例項化component,這樣就能保證該component只有一個例項
public class MyApplication extends Application {
MainActivityComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerMainActivityComponent.create();
}
public static MyApplication get(Context context) {
return (MyApplication) context.getApplicationContext();
}
public MainActivityComponent getComponent() {
return component;
}
}
在需要使用的地方,用實現單例的component進行注入即可,在這裡我們分別在兩個不同對的Activity中列印該類例項的HashCode,若是相同,就說明我們成功實現了單例.
public class MainActivity extends Activity {
@Inject
Gson gson;
@Inject
Gson gson1;
@BindView(R.id.jump)
Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
MyApplication.get(this).getComponent().inject(this);
}
@OnClick({R.id.btn})
public void onViewClicked() {
Log.e("MainActivity", car.run());
Log.e("MainActivity", "gson:" + gson.hashCode() + " gson1" + gson1.hashCode());
}
}
在另一個Activity中我們做相同的操作
public class SecondActivity extends Activity {
@BindView(R.id.secoond_btn)
Button secoondBtn;
@Inject
Gson gson;
@Inject
Gson gson1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
MyApplication.get(this).getComponent().inject(this);
}
@OnClick(R.id.secoond_btn)
public void onViewClicked() {
Log.e("SecondActivity", "gson:" + gson.hashCode()+" gson1"+gson1.hashCode());
}
}
我的測試結果如下:
E/MainActivity: gson:1111566360 gson11111566360
E/SecondActivity: gson:1111566360 gson11111566360
可以看到四個HashCode都一樣,我們的全域性單例模式算是實現了。
還有兩個註解的使用,@dependencies和subComponent有空再說吧,是用來描述component的組織關係的。