編輯:關於Android編程
現在Dagger2在項目中的使用越來越多,Dagger2是Dagger的升級版本,Dagger沒有使用過,但是本篇說的是Dagger2,主要講解的是Dagger2是如何使用的。對了,忘了說Dagger其實是一個依賴注入的框架。
依賴注入是一種面向對象的編程模式,它的出現是為了降低耦合性,所謂耦合就是類之間依賴關系,所謂降低耦合就是降低類和類之間依賴關系。可能有的人說自己之前並沒有使用過依賴注入,其實真的沒有使用過嗎?當我們在一個類的構造函數中通過參數引入另一個類的對象,或者通過set方法設置一個類的對象其實就是使用的依賴注入。
interface ClassBInterface { void setB(ClassB b); } public class ClassA implements ClassBInterface { ClassB classB; @override void setB(ClassB b) { classB = b; } }通過set方法注入
public class ClassA { ClassB classB; public void setClassB(ClassB b) { classB = b; } }通過構造方法注入
public class ClassA { ClassB classB; public void ClassA(ClassB b) { classB = b; } }通過注解的方式注入
public class ClassA { //此時並不會完成注入,還需要依賴注入框架的支持,如Dagger2 @inject ClassB classB; public ClassA() {} }
下面我們就來說說如何通過Dagger2來實現依賴注入吧。
添加apt插件
dependencies { classpath 'com.android.tools.build:gradle:2.1.2' //添加apt插件 classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' }
添加依賴(在build.gradle中添加如下代碼)
apply plugin: 'com.android.application' //添加如下代碼,應用apt插件 apply plugin: 'com.neenbedankt.android-apt' ... dependencies { ... compile 'com.google.dagger:dagger:2.4' apt 'com.google.dagger:dagger-compiler:2.4' //java注解 compile 'org.glassfish:javax.annotation:10.0-b28' ... }
添加完Dagger的依賴後我們如何在項目中使用Dagger呢?
在項目中絕大多數的使用都是Dagger結合MVP架構使用的,在MVP中使用是非常典型的降低耦合的使用。不懂MVP的可以看這裡。
本篇文章中的示例是一個簡單的登陸功能的示例,代碼沿用上篇講解MVP的登陸代碼,看這裡,該示例采用MVP架構設計通過Dagger2進行解耦合,下面就來看看如何使用吧。
在使用Dagger2前我們最好簡單的了解一下MVP,主要是為了理解本篇中的代碼。簡單了解MVP即使不會寫MVP也可以看的懂本篇的代碼。
為什麼要選擇在MVP模式中使用Dagger2呢?因為在MVP模式中Activity持有presenter的引用,同時presenter也持有view的引用,這樣便於更新UI界面,這樣Activity就和presenter僅僅的耦合在一起了,
而Dagger2是依賴注入框架就是解耦合的,所以子MVP中使用Dagger2也就再好不過了。
在上篇文章講解MVP時我們可以明顯的看到如下代碼
public class LoginActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{ private Button mLogin ; private Button mClear ; private EditText mName ; private EditText mPassWord ; ILoginPresenter loginPresenter ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLogin = (Button) findViewById(R.id.btn_login); mClear = (Button) findViewById(R.id.btn_clear); mName = (EditText) findViewById(R.id.et_name); mPassWord = (EditText) findViewById(R.id.et_password); mLogin.setOnClickListener(this); mClear.setOnClickListener(this); //持有presenter的引用並且創建對象 loginPresenter = new LoginPresenterCompl(this) ; } ........ }
在上述代碼中可以看到activity持有了presenter的引用並且創建了該對象,但是如果presenter的構造函數發生改變則這裡也需要改變,其實所有和presenter構造函數相關的代碼都要改變。
但是如果我們使用Dagger2依賴框架該如何使用呢?請看下面代碼
activity中的代碼
public class LoginActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{ .......... //注意此處使用了注解 @Inject LoginPresenterCompl loginPresenter ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLogin = (Button) findViewById(R.id.btn_login); mClear = (Button) findViewById(R.id.btn_clear); mName = (EditText) findViewById(R.id.et_name); mPassWord = (EditText) findViewById(R.id.et_password); mLogin.setOnClickListener(this); mClear.setOnClickListener(this); DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this); } ....... }
LoginPresenterCompl中的代碼
public class LoginPresenterCompl implements ILoginPresenter { private ILoginView loginView ; private User user ; //注意此處使用了注解 @Inject public LoginPresenterCompl(ILoginView view){ loginView = view ; user = new User("張三","123456") ; } ...... }
只有上述兩個注解還無法完成依賴注入,還需要如下兩個新增類
新增的MainModule類
@Module public class MainModule { private final ILoginView view ; public MainModule(ILoginView view){ this.view = view ; } @Provides ILoginView provideILogView(){ return view ; } }
新增的MainComponent接口
@Component(modules = MainModule.class) public interface MainComponent { public void inject(LoginActivity activity) ; }
通過直接注解和上述兩個接口類即可完成Dagger2的依賴注入。
在LoginActivity中是通過
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
完成依賴注入的。
看完上面的代碼後,一臉的懵逼,WTF(what the fuck),這TM是什麼,這麼復雜,還不如之前的簡單呢,新增了兩個類還有這麼多代碼,得不償失呀!
同志們,如果你們第一眼看到後是這樣想的話,說明和我想的一樣,呵呵。每一個剛接觸Dagger2的人可能都會這樣想,因為我們只看到了表面。
不錯,表面上我們是多了一個類和接口也多了很多代碼,但是這樣的組合其實是可以理解的。因為通常簡單的代碼具有耦合性,而要想降低這樣的耦合就需要其他的輔助代碼,其實少代碼量和低耦合這兩者並不能同時兼顧,古人雲:魚和熊掌不可兼得。我們作為堂堂聰明絕頂的程序猿怎麼可能會輸給古人呢。
好!下面來認真講解Dagger2是如何完成依賴注入的。
首先我們來看看LoginActivity代碼
LoginActivity中有這麼一段代碼
@Inject LoginPresenterCompl loginPresenter ;
同樣在LoginPresenterCompl中也有這麼一段代碼
@Inject public LoginPresenterCompl(ILoginView view){ loginView = view ; user = new User("張三","123456") ; }
之所以挑出這兩段代碼是因為它們都添加了@Inject注解。
在LoginActivity中其實只有這麼一句提到loginPresenter,在接下來的代碼中並沒有對其進行初始化。
那loginPresenter是如何進行初始化的呢(此處注意添加@Inject注解的變量不能被private修飾)?
直觀上我們可以這樣理解,被@Inject注解的代碼存在某種聯系,當代碼執行到@Inject的時候程序會自動進入到這個類的構造方法中,如果正巧這個構造方法也被@Inject修飾了,那麼系統就會幫我們自動創建對象。
這只是表面的理解,這其中肯定還有很多我們沒有看到的“貓膩”。這倆不會無緣無故的有聯系,肯定還有第三者,通過這個第三者這兩個被@Inject注解修飾的代碼才會產生聯系。
這個第三者是誰呢?自然的我們就會想到我們添加的這個類和接口。
首先我們來分析MainComponent接口
代碼如下
@Component(modules = MainModule.class) public interface MainComponent { public void inject(LoginActivity activity) ; }
MainComponent是一個接口(也可以是一個抽象類),在這個接口中我們定義了一個inject()方法,其中參數是LoginActivity對象,同時MainComponent還被@Component注解著,注解中modules的值是MainModule.class,這個內容會在接下來的地方進行說明,暫時先放一放。
此時在Android studio中,如果我們rebuild的一下項目就會有新的發現。在項目的build/generated/source/apt/debug/項目包名/dragger目錄下生成對應的包其中包含DaggerMainComponent類,這個類名其實不是固定的,是根據我們上面寫的MainComponent,加了Dagger前綴生成的DaggerMainComponent。
其實在這個時候我們就已經完成了present的依賴注入。
但是在
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
中我們看到還有一個MainModule,這個是我們自己創建的一個類
MainModule代碼如下
@Module public class MainModule { private final ILoginView view ; public MainModule(ILoginView view){ this.view = view ; } @Provides ILoginView provideILogView(){ return view ; } }
我們可以看到這個類被@Module注解修飾,內部有一個ILoginView的變量和一個構造方法還有一個被@Provides修飾的provideILogView方法。
看到這還是一臉懵逼,這個類是干嘛的?
在MainComponent接口中我們看到這麼一個注解@Component(modules = MainModule.class),這裡用到了MainModule,可見MainComponent需要MainModule一起才能完成工作。
其實這個類我們可以理解成提供參數的,也就是提供參數依賴的,如何理解呢?
在MainModule中我們為什麼要提供ILoginView類型的對象?為什麼不是其他的呢?
這是因為LoginPresenterCompl的構造函數需要這麼一個參數,所以我們在這裡提供這麼一個相同的參數,並通過被@Provides注解修飾的方法將其返回出去,如果LoginPresenterCompl還需要其他的參數,同樣我們也可以在這裡添加對應類型的參數然後通過另一個被@Provides注解修飾的方法返回出去。
在MainComponent接口中提供的inject()方法的參數是LoginActivity,這個參數的含義是LoginPresenter要在什麼地方注入。
了解了各個類的功能後我們來總結一下
@Inject 程序會將Dagger2會將帶有此注解的變量或者構造方法參與到依賴注入當中,Dagger2會實例化這個對象
@Module 帶有該注解的類需要對外提供依賴,其實就是提供實例化需要的參數,Dagger2在實例化的過程中發現一些參數,Dagger2就會到該類中尋找帶有@Provides注解的以provide開頭的需找對應的參數
@Component 帶有該注解的接口或抽象類起到一個關聯橋梁的作用,作用就是將帶有@Inject的方法或對象和帶有@Module的類進行關聯,只有通過該接口或抽象類才可以在實例化的時候到帶有
@Module中類中去尋找需要的參數,也就是依賴注入。
OK,下面我們來捋捋思路。
1、在這個示例代碼中,LoginActivity中需要LoginPresenterCompl,所以在LoginActivity中定義了該對象並且通過@Inject將其注解,同時到LoginPresenterCompl的構造方法中也通過@Inject將其注解,
表明這些是需要依賴注入的。
2、因為在LoginPresenterCompl的構造方法需要ILoginView類型的參數,所以需要通過依賴將獲取這些參數,所以就需要帶有@Module注解的類用於獲取需要的參數,
在@Module注解的類中通過被@Provides注解的以provide開頭的方法對外提供需要的參數,一般而言有幾個參數就需要有幾個帶有@Provides的方法。
3、此時還需要一個橋梁將兩者聯系到一起,帶有@Component的接口或抽象類就起到這個橋梁的作用。注解中有一個module的值,這個值指向需要依賴的Module類,同時其中有一個抽象方法
inject(),其中的參數就是我們需要在哪個類中實例化LoginPreserentCompl,因為我們需要在LoginActivity中實例化,所以參數類型就是LoginActivity類型。
然後在Android studio中rebuild我們的項目,就會生成DaggerMainComponent類,通過
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);
完成我們需要的依賴注入。
可能我們通過上面的講解,知道了如何使用Dagger2了,也知道具體的流程了,但是可能還會有些疑惑,為什麼?Dagger2是如何通過一些接口和類就完成依賴注入的?
在此聲明,別著急,知道如何使用這只是第一步,在下一篇文章中將會講解Dagger2實現依賴注入的原理。敬請期待!!!
一、利用普通的Adapter實現ListView列表——這是最基礎的適配器以下代碼是最普通的實現方法:1、MainActiviy.ja
Java文件大小轉換工具類 (B,KB,MB,GB,TB,PB之間的大小轉換) 有時候要做出如下所示的展示文件大小的效果時候,需要對文件大小進行轉換,然後再進行相關的代碼
本文是自己學習所做筆記,歡迎轉載,但請注明出處:http://blog.csdn.net/jesson20121020 上節實現了查看圖片及錄音的
上一篇博客中我們已經繪制出了一個直角三角形,雖然我們相對於坐標,我們設置的直角三角形的兩腰是相等的,但是實際上展示出來的卻並不是這樣,雖然通過計算,我們可以把三角形的兩腰