RoboGuice 3.0 (三)總結篇

来源:http://www.cnblogs.com/pedro-neer/archive/2016/03/09/5257037.html
-Advertisement-
Play Games

經過前兩篇的介紹,我們瞭解瞭如何使用RoboGuice方便的為我們註入需要的對象,這篇將著重說明原理。 一.Guice與RoboGuice Guise是Google開發的一個輕量級的依賴註入框架,主要針對Java使用的。 RoboGuice是基於Guice庫開發,目的為Android提供一套簡單易用


經過前兩篇的介紹,我們瞭解瞭如何使用RoboGuice方便的為我們註入需要的對象,這篇將著重說明原理。

一.Guice與RoboGuice

Guise是Google開發的一個輕量級的依賴註入框架,主要針對Java使用的。

RoboGuice是基於Guice庫開發,目的為Android提供一套簡單易用的依賴註入框架。

上兩篇中所提到的POJO註入,說白了就是對象註入,大部分方法都是Guice框架中的。RoboGuice主要在視圖註入及Android個性化的註入上下功夫。

二.RoboGuice註入對象

就算沒用過RoboGuice,但是大家也都聽過,RoboGuice是通過反射來實現註入的。

為了瞭解實現的原理,我們先看下RoboActivity的代碼。
其中eventManager初始化方式使用的就是之前提過的RoboGuice.getInjector(),其內部提供了各種事件的註冊,反註冊,分發等等功能。

public class RoboActivity extends Activity implements RoboContext {
    protected EventManager eventManager;
    protected HashMap<Key<?>,Object> scopedObjects = new HashMap<Key<?>, Object>();

    @Inject ContentViewListener ignored; // BUG find a better place to put this
    private Stopwatch stopwatch;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        stopwatch = new Stopwatch();
        final RoboInjector injector = RoboGuice.getInjector(this);
        stopwatch.resetAndLog("RoboActivity creation of injector");
        eventManager = injector.getInstance(EventManager.class);
        stopwatch.resetAndLog("RoboActivity creation of eventmanager");
        injector.injectMembersWithoutViews(this);
        stopwatch.resetAndLog("RoboActivity inject members without views");
        super.onCreate(savedInstanceState);
        stopwatch.resetAndLog("RoboActivity super onCreate");
        eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
        stopwatch.resetAndLog("RoboActivity fire event");
    }
}

其次註意到被註入的ContentViewListener,這就是為了實現在Activity上的ContentView的註解,這裡的方法是

@ContextSingleton
public class ContentViewListener {
    @Inject protected Activity activity;

    public void optionallySetContentView( @Observes OnCreateEvent<?> ignored ) {
        Class<?> c = activity.getClass();
        while( c != Context.class ) {
            final ContentView annotation = c.getAnnotation(ContentView.class);
            if( annotation!=null ) {
                activity.setContentView(annotation.value());
                return;
            }
            c = c.getSuperclass();
        }
    }
}

這裡觀察的是OnCreate的事件,事件的分發代碼在OnCreate方法中,實現了setContentView的方法。

onCreate方法簡化後如下。可以發現inject對象的時機是在super的onCreate之前的,

@Override
    protected void onCreate(Bundle savedInstanceState) {
        final RoboInjector injector = RoboGuice.getInjector(this);
        eventManager = injector.getInstance(EventManager.class);
        injector.injectMembersWithoutViews(this);
        super.onCreate(savedInstanceState);
        eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
    }

RoboInjector其實是RoboGuice內部的一個Guice Injector,大部分註入工作交給了Guice。

反射註入這一塊就不深入討論了,下麵貼出了Guice的部分代碼。

private static void computeInjectableMembers(TypeLiteral<?> type, boolean statics, Errors errors, InjectionPoint.InjectableMembers injectableMembers, InjectionPoint.OverrideIndex overrideIndex, HierarchyTraversalFilter filter) {
    Class rawType = type.getRawType();
    if(isWorthScanning(filter, rawType)) {
        Class parentRawType = rawType.getSuperclass();
        if(isWorthScanning(filter, parentRawType)) {
            computeInjectableMembers(type.getSupertype(parentRawType), statics, errors, injectableMembers, overrideIndex, filter);
            overrideIndex.position = InjectionPoint.Position.MIDDLE;
        } else {
            overrideIndex.position = InjectionPoint.Position.TOP;
        }

        Set allFields = filter.getAllFields(Inject.class.getName(), rawType);
        if(allFields != null) {
            Iterator allMethods = allFields.iterator();

            while(allMethods.hasNext()) {
                Field i$ = (Field)allMethods.next();
                if(Modifier.isStatic(i$.getModifiers()) == statics) {
                    Annotation method = getAtInject(i$);
                    if(method != null) {
                        InjectionPoint.InjectableField atInject = new InjectionPoint.InjectableField(type, i$, method);
                        if(atInject.jsr330 && Modifier.isFinal(i$.getModifiers())) {
                            errors.cannotInjectFinalField(i$);
                        }

                        injectableMembers.add(atInject);
                    }
                }
            }
        }

        Set allMethods1 = filter.getAllMethods(Inject.class.getName(), rawType);
        if(allMethods1 != null) {
            Iterator i$1 = allMethods1.iterator();

            while(true) {
                while(true) {
                    while(true) {
                        Method method1;
                        do {
                            if(!i$1.hasNext()) {
                                return;
                            }

                            method1 = (Method)i$1.next();
                        } while(!isEligibleForInjection(method1, statics));

                        Annotation atInject1 = getAtInject(method1);
                        if(atInject1 != null) {
                            InjectionPoint.InjectableMethod removed2 = new InjectionPoint.InjectableMethod(type, method1, atInject1);
                            if(!checkForMisplacedBindingAnnotations(method1, errors) && isValidMethod(removed2, errors)) {
                                if(statics) {
                                    injectableMembers.add(removed2);
                                } else {
                                    overrideIndex.removeIfOverriddenBy(method1, true, removed2);
                                    overrideIndex.add(removed2);
                                }
                            } else {
                                boolean removed1 = overrideIndex.removeIfOverriddenBy(method1, false, removed2);
                                if(removed1) {
                                    logger.log(Level.WARNING, "Method: {0} is not a valid injectable method (because it either has misplaced binding annotations or specifies type parameters) but is overriding a method that is valid. Because it is not valid, the method will not be injected. To fix this, make the method a valid injectable method.", method1);
                                }
                            }
                        } else {
                            boolean removed = overrideIndex.removeIfOverriddenBy(method1, false, (InjectionPoint.InjectableMethod)null);
                            if(removed) {
                                logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but is overriding a method that is annotated with @javax.inject.Inject.  Because it is not annotated with @Inject, the method will not be injected. To fix this, annotate the method with @Inject.", method1);
                            }
                        }
                    }
                }
            }
        }
    }
}

三.總結

這三篇過來,依賴註入給我們帶來了什麼?

解耦。

當我們在一個對象中,不需要關心它所依賴的成員如何初始化,只關心用來使用或獲取屬性,依賴註入為我們實現瞭解耦。

再就是RoboGuice的貼心,將Android基本組件考慮在內,為我們實現了很多註入,減少了我們調用系統服務或組件的代碼,再就是RoboGuice考慮到了Android生命周期的特殊問題,將註入的成員對象生命周期保持與Context生命周期一致。

再說說反射,儘管RoboGuice強調,使用roboblender會優化很大一部分註解性能,但是反射對於移動端設備參差不齊的配置,還是讓人有一點點擔心,如果項目足夠大,且使用了大量的註解及註入,那麼性能一定是有影響的。

最後,RoboGuice確實是一個值得使用的框架,使用簡單、上手較快、能實現模塊解耦。光憑這幾點優點便足以打動人心。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • <?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_par
  • <?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_par
  • andriod ==和equals
  • 前言:本隨筆將對IOS開發的支付功能進行一個概述。 內容大綱: 一、常見的支付方案簡介 二、第三方支付SDK 三、蘋果官方支付方案 四、Web支付方案 正文: 一、常見的支付方案簡介 在微信支付中 微信支付的網址是: https://pay.weixin.qq.com/wiki/doc/api/in
  • 一個例子 package sortt; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class HomeWor
  • 許可權 說明 ACCESS_NETWORK_STATE 允許應用程式獲取網路狀態信息的許可權 ACCESS_WIFI_STATE 允許應用程式獲取 Wi-Fi 網路狀態的許可權 BATTERY_STATE 允許應用程式獲取電池專題信息的許可權 BLUETOOTH 允許應用程式連接匹配的藍牙設備的許可權 BLU
  • 在一些項目中,我們需要自定義自己的UIButton,使Button上面同時具有圖片和文字描述,實現自定義UIButton的圖文混排。 首先我們需要定義一個繼承自UIButton的類,同時實現自己的initWithFrame:方法。方法聲明在這個類的頭文件中。 self = [super initWi
  • category與associative作為objective c的擴展機制的兩個特性,category即類型,可以通過它來擴展方法;associative,可以通過它來擴展屬性;在iOS開發中,可能category比較常見,相對的associative,就用的比較少,要用它必須使用的頭文件,然後就
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...