Android註解使用之Dagger2實現項目依賴關係解耦

來源:互聯網
上載者:User

標籤:oid   sso   etc   default   multiple   地方   添加   最小   google   

前言:

   最近牽頭髮起公司app的重構工作,如何通過重構讓項目的耦合降低、開發效率提高,一直是我努力的方向,今天來學習一下一個註解架構Dagger2,然後看看如何使用它來降低項目的耦合。    

Dagger2

    一句話:一款快速的註解架構,應用於Android、Java,由 Google 開發和維護,是 Square 的 Dagger 項目的分支。

    gitHub:https://github.com/google/dagger

    Dagger2採用依賴注入方式,依賴注入是一種物件導向的編程模式,它的出現是為了降低耦合性,所謂耦合就是類之間依賴關係,所謂降低耦合就是降低類和類之間依賴關係。

依賴關係

   Java的物件導向編程特性,通常會在一個Java對象中引用另一個Java對象,舉例說明一下:

public class ClassA {    private ClassB classB;    public ClassA(){        classB =new ClassB();    }    public  void doSomething(){        classB.doSomething();    }}

通過上面的例子可以看出,ClassA需要藉助ClassB才能完成一些特定操作,但是我們在ClassA直接執行個體化了ClassB,這樣耦合就產生了,第一違背了單一職責原則,ClassB的執行個體化應該由自己完成,不應該由ClassA來完成,第二違背了開閉原則,一旦ClassB的建構函式產生變化,就需要修改ClassA的建構函式。

通過依賴注入降低這種耦合關係:

1.通過構造參數傳參的方式

public class ClassA {    private ClassB classB;    public ClassA(ClassB classB){        this.classB =classB;    }    public  void doSomething(){        classB.doSomething();    }}

2.通過set方法的方式

public class ClassA {    private ClassB classB;    public ClassA(){    }    public void setClassB(ClassB classB) {        this.classB = classB;    }    public  void doSomething(){        classB.doSomething();    }}

3.通過介面注入的方式

interface ClassBInterface {    void setB(ClassB classB);}public class ClassA implements ClassBInterface {    private ClassB classB;    public ClassA() {    }    @Override    public void setB(ClassB classB) {        this.classB = classB;    }    public void doSomething() {        classB.doSomething();    }}

4.通過註解注入

public class ClassA {    @Inject    ClassB classB;    public ClassA() {    }    public void doSomething() {        classB.doSomething();    }}

Dagger2採用的就是註解注入的方式,然後編譯自動產生目標代碼的方式實現宿主與被依賴者之間的關係。

Dagger2在Android的使用方式及簡單說明

在Android中的使用方式很簡單:只需在Module的build.gradle中添加一下配置

dependencies {  compile ‘com.google.dagger:dagger:2.x‘  annotationProcessor ‘com.google.dagger:dagger-compiler:2.x‘}

 Dagger2 annotation講解

  • @Module 修飾的類專門用來提供依賴

  • @Provides 修飾的方法用在Module類裡

  • @Inject  修飾需要依賴的地方(可以是構造方法、field或者一般的方法)

  • @Component 串連@Module和注入的橋樑

Dagger2舉例說明

 以項目中實際情境緩衝管理為例,來體驗一下解耦效果。設計遵循單一職責原則。

 1.首先定義緩衝類和多任務類。並且在其建構函式上添加@Inject註解

LCache類

/** * Created by lichaojun on 2017/3/30. * 處理緩衝 */public class LCache {    private static  final  String DEFAULT_CACHE_NAME="LCache";//預設緩衝名字    private static  final  int DEFAULT_MAX_CACHE_SIZE=1024;//預設緩衝名字    private String cacheName=DEFAULT_CACHE_NAME;//緩衝名字    private int maxCacheSize=DEFAULT_MAX_CACHE_SIZE;    public LCache (){    }    @Inject    public  LCache(String cacheName,int maxCacheSize){        this.cacheName=cacheName;        this.maxCacheSize=maxCacheSize;    }    public void saveCache(String key ,String value){        Log.e(LCacheManager.TAG,"cacheName:  = "+cacheName);        Log.e(LCacheManager.TAG,"maxCacheSize:  = "+maxCacheSize);        Log.e(LCacheManager.TAG,"saveCache: key = "+key +" value = "+value);    }    public  void readCache(String key){        Log.e(LCacheManager.TAG,"readCache: key:  = "+key);    }}

LExecutor類

public class LExecutor {    private static final int DEFAULT_CPU_CORE = Runtime.getRuntime().availableProcessors();//預設線程池維護線程的最少數量    private int coreSize = DEFAULT_CPU_CORE;//線程池維護線程的最少數量    @Inject    public LExecutor(int coreSize) {        this.coreSize = coreSize;    }    public void runTask(Runnable runnable) {        if (runnable == null) {            return;        }        Log.e(LCacheManager.TAG,"coreSize:  = "+coreSize);        Log.e(LCacheManager.TAG, "runTask");        runnable.run();    }}
2.使用@Module分別定義LCacheModule、LExecutorModule類來提供相關依賴

LCacheModule類

@Modulepublic class LCacheModule {    /**     * 提供緩衝對象     * @return 返回緩衝對象     */    @Provides    @Singleton    LCache provideLCache() {        return new LCache("lcj",500);    }}

LExecutorModule類

@Modulepublic class LExecutorModule {    /**     * 提供app 多任務最少維護線程個數     * @return 返回多任務最少維護線程個數     */    @Provides    @Singleton    LExecutor provideLExecutor() {        return new LExecutor(10);    }}
3.使用@Component 用來將@Inject和@Module關聯起來,建立LCacheComponent類
@Component(modules = {LCacheModule.class,LExecutorModule.class})@Singletonpublic interface LCacheComponent {    LCache lCache();   // app緩衝    LExecutor lExecutor();  // app多任務線程池    void inject(LCacheManager lCacheManager);}
4.在宿主中注入想要依賴的對象
/**
* Created by lichaojun on 2017/3/30.
* 緩衝處理管理
*/
public class LCacheManager {
public static final String TAG=LCacheManager.class.getSimpleName();
private LCacheComponent cacheComponent;

private static class SingletonHolder {
private static LCacheManager instance = new LCacheManager();
}

private LCacheManager(){
cacheComponent = DaggerLCacheComponent.builder().lCacheModule(new LCacheModule()).build();
cacheComponent.inject(this);
}

public static LCacheManager getInstance() {
return SingletonHolder.instance;
}

public void saveCache(final String key , final String value) {
cacheComponent.lExecutor().runTask(new Runnable() {
@Override
public void run() {
cacheComponent.lCache().saveCache(key,value);
}
});
}

public void readCache(final String key){
cacheComponent.lExecutor().runTask(new Runnable() {
@Override
public void run() {
cacheComponent.lCache().readCache(key);
}
});
}
}
5.使用情境調用及簡單解說
LCacheManager.getInstance().saveCache("key","who is lcj ?");

看下列印結果:

通過Dagger2的方式剛開始可能會覺得突然間一個簡單的事情,變得複雜了,其實沒有,通過Dagger2很好的處理好了依賴關係,具體說明,比如我們緩衝LCache需要添加一個最大緩衝個數變化,如果按照之前的方式,我們首先需要對LCache進行修改,比如修改建構函式增加maxCacheSize,然後必須對LCacheManager進行修改,現在通過Dagger2的方式的話,我們只需修改LCacheModule就可以了,LCache執行個體化和相關參數和LCacheManager之間並沒有太大的依賴關係。

6.關於@Module提供多個同類型@Provides

 基於上面的緩衝處理需求,我們需要實現讀寫分別使用不同的多任務LExecutor,並且LExecutor的最小線程數為5,我們會在LCacheComponent添加提供writeLExecutor函數,如下:

@Component(modules = {LCacheModule.class,LExecutorModule.class})@Singletonpublic interface LCacheComponent {    LCache lCache();   // app緩衝    LExecutor lExecutor();  // app多任務線程池    LExecutor writeLExecutor();  // app 寫緩衝多任務線程池    void inject(LCacheManager lCacheManager);}

在LExecutorModule中添加提供依賴初始化的provideWriteLExecutor函數。如下:

@Modulepublic class LExecutorModule {    /**     * 提供app 多任務最少維護線程個數     * @return 返回多任務最少維護線程個數     */    @Provides    @Singleton    LExecutor provideLExecutor() {        return new LExecutor(10);    }    /**     * 提供app 多任務最少維護線程個數     * @return 返回多任務最少維護線程個數     */    @Provides    @Singleton    LExecutor provideWriteLExecutor() {        return new LExecutor(5);    }}

然後寫完之後Rebuild一下項目,以為萬事大吉了,結果報了如下錯誤,

怎麼辦呢,難道Dagger2就這麼不堪一擊嗎,當然不是解決這個問題很容易,使用@Named註解解決這個問題,我們只需要在LCacheComponent的writeLExecutor()和

LExecutorModule的provideWriteLExecutor()函數上添加相同的@Named("WriteLExecutor")即可。

對於Module的provide函數也是可以傳遞參數的,不過需要在當前Module中需要提供相關的參數的函數。例如:LCacheModule可以修改如下:

@Modulepublic class LCacheModule {    /**     * 提供緩衝對象     * @return 返回緩衝對象     */    @Provides    @Singleton    LCache provideLCache( @Named("LCache")String name , @Named("LCache")int maxCacheSize) {        return new LCache(name,maxCacheSize);    }    /**     * 提供緩衝對象     * @return 返回緩衝對象     */    @Provides    @Singleton    @Named("LCache")    String provideLCacheName() {        return "lcjCache";    }    /**     * 提供緩衝對象     * @return 返回緩衝對象     */    @Provides    @Singleton    @Named("LCache")    int provideLCacheMaxSize() {        return 600;    }}

這裡又使用了別名@Name也是因為為了避免bound multiple times錯誤導致編譯失敗,在編譯的過程中Dagger2會自動去尋找相關參數進行繫結相依性,這點還是挺神奇的。

總結:

  今天簡單的寫個例子對Dagger2有個初步的理解與認識,由於項目並沒有採用MVP設計模式,準備逐步採用Dagger2+MVP來降低項目中耦合。

 

Android註解使用之Dagger2實現項目依賴關係解耦

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.