什么是依賴(lài)注入
依賴(lài)注入(Dependency Injection)钥屈,簡(jiǎn)單理解A持有B的依賴(lài)讹开,通過(guò)構(gòu)造函數(shù)或者setter方法將B的實(shí)例傳入A就是依賴(lài)注入咐熙。
關(guān)于Dagger2
Dagger2是在編譯期根據(jù)注解通過(guò)APT自動(dòng)生成模板代碼的方式實(shí)現(xiàn)依賴(lài)注入挺举。編譯期注解比反射性能更好杀赢,解耦更徹底,方便測(cè)試湘纵。
github地址:https://github.com/google/dagger
官網(wǎng):https://dagger.dev/
使用
主要的注解:
- @Inject 標(biāo)記被依賴(lài)對(duì)象的構(gòu)造方法和依賴(lài)方的成員變量
- @Component 標(biāo)識(shí)依賴(lài)注入類(lèi)脂崔,該類(lèi)注入方法,參數(shù)為接收注入的對(duì)象
- @Module 標(biāo)識(shí)依賴(lài)提供類(lèi)梧喷,其@Provides方法的返回值表示提供的依賴(lài)對(duì)象
- @Provides 標(biāo)識(shí)@Module類(lèi)中的public方法砌左,方法帶參時(shí)dagger會(huì)遞歸查找參數(shù)被@Inject標(biāo)記的構(gòu)造方法以提供實(shí)例
- @Scope 依賴(lài)注入對(duì)象的作用域,通過(guò)自定義被@Scope注解的注解可以控制依賴(lài)注入對(duì)象的作用范圍铺敌。@Singleton是它的一個(gè)默認(rèn)實(shí)現(xiàn)汇歹,其單例是在component的生命周期內(nèi),如果多個(gè)類(lèi)中用不同的component對(duì)象注入得到的是不同實(shí)例
- @Qualifier 同@Name類(lèi)似适刀,如果有兩個(gè)@Provides方法的返回值一樣可以通過(guò)@Qualifier或者@Name區(qū)分
- @Name
MVP+Dagger2
MVP應(yīng)該是android開(kāi)發(fā)應(yīng)用最廣泛的框架了秤朗,其將視圖層view、邏輯層presenter和數(shù)據(jù)層model分開(kāi)各自負(fù)責(zé)不同的功能笔喉,通過(guò)接口回調(diào)處理結(jié)果取视。結(jié)合Dagger后可以使解耦更加徹底硝皂,更加方便管理依賴(lài),但同時(shí)也提高了學(xué)習(xí)成本作谭,實(shí)現(xiàn)一個(gè)簡(jiǎn)單功能MVP原本就需要?jiǎng)?chuàng)建大量的類(lèi)現(xiàn)在更加復(fù)雜稽物。瑕不掩瑜,有人根據(jù)MVP和Dagger開(kāi)發(fā)了很多實(shí)用框架折欠,arms就是一個(gè)不錯(cuò)的框架 https://github.com/JessYanCoding/MVPArms 下面要寫(xiě)的就是一個(gè)簡(jiǎn)化版Demo
正文
已登錄為例首先創(chuàng)建MVP必要的組件LoginActivity贝或、LoginPresenter、LoginContract.View锐秦、LoginContract.Model
這里L(fēng)oginActivity不是真正的Activity只是為了方便說(shuō)明MVP模式
public class LoginActivity implements LoginContract.View {
@Inject
public LoginPresenter mPresenter;
public LoginActivity() {
}
public void login(String id, String pwd) {
// Presenter尚未注入咪奖,此時(shí)mPresenter為null
mPresenter.login(id, pwd);
}
@Override
public void refreshUI() {
System.out.println("LoginActivity refresh UI");
}
public static void main(String[] args) {
LoginActivity loginActivity = new LoginActivity();
loginActivity.login("xiaoming", "123");
}
}
成員變量持有LoginPresenter的依賴(lài),Dagger會(huì)根據(jù)@Inject注解優(yōu)先查找LoginPresenter被@Inject注解的構(gòu)造函數(shù)酱床,如果有參數(shù)就遞歸查找參數(shù)被@Inject注解的構(gòu)造函數(shù)
public class LoginPresenter extends BasePresenter<LoginContract.Model, LoginContract.View>{
@Inject
public LoginPresenter(LoginContract.Model model, LoginContract.View view) {
super(model, view);
System.out.println("LoginPresenter constructor is invoked");
}
public void login(String id, String pwd) {
System.out.println("LoginPresenter login() id = "+id +", pwd = "+pwd);
boolean login = mModel.login("id = " + id + ", pwd = " + pwd);
if (login) {
mRootView.refreshUI();
}
}
}
public interface LoginContract {
interface View extends IView{
void refreshUI();
}
interface Model extends IModel{
boolean login(String params);
}
}
回調(diào)接口View和Model由contract管理羊赵,LoginModel實(shí)現(xiàn)LoginContract.Model, presenter持有model依賴(lài)由dagger根據(jù)@Inject提供
public class LoginModel implements LoginContract.Model {
@Inject
public LoginModel() {
System.out.println("LoginModel constructor is invoked");
}
@Override
public boolean login(String params) {
System.out.println("LoginModel login() is invoked params = "+params);
return true;
}
}
View實(shí)現(xiàn)在LoginActivity中,Component注入時(shí)傳入Module扇谣,由Module的provide方法提供
@Module
public class LoginModule {
private LoginContract.View view;
public LoginModule(LoginContract.View view) {
this.view = view;
}
@Provides
public LoginContract.View provideView() {
return this.view;
}
@Provides
public LoginContract.Model provideModel(LoginModel model) {
return model;
}
}
最后LoginComponent接口提供inject注入方法并指明提供依賴(lài)的Module
@Component(modules = LoginModule.class)
public interface LoginComponent {
void inject(LoginActivity loginActivity);
}
以上各類(lèi)創(chuàng)建完成后編譯一下項(xiàng)目昧捷,Dagger會(huì)根據(jù)Component自動(dòng)生成類(lèi)名為Dagger+LoginComponent格式的注入類(lèi),在LoginActivity中完成注入
public LoginActivity() {
DaggerLoginComponent.builder()
.loginModule(new LoginModule(this))
.build()
.inject(this);
}
最后可以把部分常用代碼封裝進(jìn)基類(lèi)中
public class BaseActivity<P extends BasePresenter> {
@Inject
public P mPresenter;
public BaseActivity() {
}
}
public class BasePresenter<M extends IModel, V extends IView> {
protected M mModel;
protected V mRootView;
public BasePresenter(M model, V view) {
mModel = model;
mRootView = view;
}
}
結(jié)語(yǔ)
Dagger還有許多用法就不一一列舉了,最后還是感謝開(kāi)源感謝arms的作者(傳送門(mén)https://github.com/JessYanCoding)