今天要來繼續Dagger第二階段撰寫,今天的進度會與@Singleton
、@Binds
的更進階一點的註解標籤來新增並實作,在實作之前我要再來說明何謂Singleton單例化
的功能與用途。
Singleton 是一種設計模式,其目的是確保某個類別只有一個實例,並提供一個全局訪問點來存取該實例。
它會在內存中建立該對象的唯一實例。每次注入該對象時,Dagger 2 都會返回這個唯一的實例。
於同一個class
只會做一次New
的動作,後續若再次呼叫class
時會判定class
是否已經被實例化了,若有被實例化過就不會再次進行New
的動作,而是直接使用原本已經實例化的物件。
Double-checked locking(雙重檢查鎖定模式)
的方式來檢查是否有被初始化過。創造一個靜態的特殊 method,呼叫這個方法時,先檢查物件是否已被實體化,若已被實體化,直接回傳該物件的一個參照;尚未被實體化的話,就回傳一個新實體的參照。
這邊先放上效果呈現圖,此圖是我在過去第一次實作時的結果圖,由此可見到在Worker添加了@Singleton
之後的效果,圖例-壹可看到Worker有@59a2db
和@92da051
兩個代號,而添加後的圖例-貳中只有@59a2db
一個代號。
@Singleton
註解標籤,log出來的結果會是兩個不同的人物。@Singleton
標籤註解之後,所顯示的Log結果是同一個人物。@Binds
注釋必須用於抽象方法上,並且方法必須返回指定的類型。此外,該方法必須位於Module
的抽象類別中。Class
,無法同時輸出多個結果,要同時輸出多個結果必須使用@Provides
註解。首先先放上資料夾圖片對比
建立@Binds
的修改步驟
EducationSystem.class
在外部Independent_School
、State_School
在school資料夾School
類型改成Interface。Independent_School
、State_School
的Module檔案。public interface School {
// 將School改成Interface介面。
void buildSchoolType();
}
下面的各個學校類別的class都要implement interfaceSchool
,並引入interface中的方法時做
public class Independent_School implements School {
// 私立學校
private static final String TAG = "Independent_School";
@Inject
public Independent_School() {
}
@Override
public void buildSchoolType() {
Log.e(TAG, "buildSchoolType: "+ TAG );
}
}
public class State_School implements School{
// 公立&國立學校
private static final String TAG = "State_School";
@Inject
public State_School() {
Log.e(TAG, "State_School OK!");
}
@Override
public void buildSchoolType() {
Log.e(TAG, "buildSchoolType: "+ TAG );
}
}
@Module
public abstract class IndependentSchoolModule {
@Binds
abstract School bindIndependentSchool(Independent_School independent_school);
}
@Module
public abstract class StateSchoolModule {
@Binds
abstract School bindStateSchool(State_School state_school);
}
public class MainActivity extends AppCompatActivity {
@Inject
EducationSystem educationSystem;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... 建立時產生的程式碼省略
SchoolComponent schoolComponent = DaggerSchoolComponent.create();
schoolComponent.inject(this);
educationSystem.start();
}
}
@Component(modules = {StudentModule.class,
TeacherModule.class,
StateSchoolModule.class})
public interface SchoolComponent {
School getSchool();
void inject(MainActivity mainActivity);
}
以上是添加@Binds
的結果,在這邊前面建立好的Student和Teacher不需要更改。
@Singleton
public class Director {
@Inject
public Director(){
}
}
public class EducationSystem {
// ...前面已建立過的程式碼 省略
private Director director;
// 建構元中添加Director。
@Inject
public EducationSystem(School school, Student student, Teacher teacher, Director director) {
this.school = school;
this.student = student;
this.teacher = teacher;
this.director = director;
}
// 稍微修改一下此Function。
public void start(){
school.buildSchoolType();
Log.e(TAG, "EducationSystem: \n" +
"school: " + school + "\n" +
"director: " + director + "\n" +
"teacher: " + teacher + "\n" +
"student: " + student + "\n" +
"Prepare OK!");
}
}
到這邊可能會覺得已經建立好了@Singleton
,但會發現運行後還是會出錯,這時只要在回到Component的類別中,在最上方加入@Singleton
的標籤即可。
@Singleton
// 以下程式碼不須變動
@Component(modules = {StudentModule.class,
TeacherModule.class,
StateSchoolModule.class})
public interface SchoolComponent {
School getSchool();
void inject(MainActivity mainActivity);
}
以上這邊就完全建立好@Singleton
以及@Binds
的功能。
下面來看一下有@Singleton
以及沒有@Singleton
的結果:
有@Singleton
沒有@Singleton
可以看到Director的結果產生了兩種不同的結果。
公立/私立
的Module時,在Build的時候就會出現問題,錯誤訊息截圖如下:Module
(IndependentSchoolModule 和 StateSchoolModule),它們都試圖綁定同一個類型的依賴 School
。這是造成錯誤的原因之一。@Singleton
標籤並Debug或Run則會出現問題,錯誤訊息截圖如下:(未設置**Scope**)試圖使用具有
@Singleton
Scope 的 Director(主任類別),這是不允許的,因為Scope不相容。@Singleton
標籤註解。以上是今天@Singleton
、@Binds
的說明與添加實作,由於在添加了@Name
以及制式化標籤註解
後可能篇幅會偏多,這邊放到明天繼續實作,並在明天添加說明@Scope
自製標籤以及其他功能標籤的說明。