在Dagger 2中使用RxJava來進行異步注入

uvqr6246 7年前發布 | 6K 次閱讀 Dagger RxJava Android開發 移動開發

在Dagger 2中使用RxJava來進行異步注入

幾星期前我寫了一篇關于在Dagger 2中使用 Producers 進行異步注入的 文章 。在后臺線程中執行對象的初始化又一個很好的優勢 - 它負責實時( 每秒60幀 可以保持界面流暢)繪制UI時不會在主線程中阻塞。

值得一提的是,緩慢的初始化過程并不是每個人都會覺得是個問題。但是如果你真的關心這個,所有外部庫在構造以及在任何 init() 方法中進行磁盤/網絡的操作會很常見。如果你不能確定這一點,我建議你嘗試下 AndroidDevMetrics - 我的Android性能測量庫。它會告訴你在app中需要花多少時間來顯示特定的界面,還有(如果你使用了Dagger 2)在依賴圖表中提供每個對象消耗了多少時間。

不幸的是Producers并不是為Android設計的,它有以下缺陷:

  • 依賴使用了Guava(會引起64k方法問題,增加build時間)
  • 并不是非常快的(注入機制會阻塞主線程幾毫秒到幾十毫秒的世界,這取決于設備)
  • 不能使用@Inject注解 (代碼會有一點混亂)

雖然我們不能解決最后兩個問題,但是第一個我們可以在Android Project中解決。

使用RxJava進行異步注入

幸運的是,有大量的Android開發者使用了RxJava(和 RxAndroid )來在我們app中編寫異步代碼。讓我們來嘗試在Dagger 2中使用它來進行異步注入。

這是我們繁重的對象:

@Provides
@Singleton
HeavyExternalLibrary provideHeavyExternalLibrary() {
    HeavyExternalLibrary heavyExternalLibrary = new HeavyExternalLibrary();
    heavyExternalLibrary.init(); //This method takes about 500ms
    return heavyExternalLibrary;
}

現在讓我們來創建一個額外的 provide...() 方法,它返回一個 Observable<HeavyExternalLibrary> 對象,它會異步調用以下代碼:

@Singleton
@Provides
Observable<HeavyExternalLibrary> provideHeavyExternalLibraryObservable(final Lazy<HeavyExternalLibrary> heavyExternalLibraryLazy) {
    return Observable.create(new Observable.OnSubscribe<HeavyExternalLibrary>() {
        @Override
        public void call(Subscriber<? super HeavyExternalLibrary> subscriber) {
            subscriber.onNext(heavyExternalLibraryLazy.get());
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}

讓我們逐行來分析:

  • @Singleton - 記住這個很重要, Observable 對象將會是一個單例,而不是 HeavyExternalLibrary 。Singleton也會阻止創建額外的Observable對象。
  • @Providers - 因為這個方法是 @Module 注解了的類的一部分。你還記得 Dagger 2 API 嗎?
  • Lazy<HeavyExternalLibrary> heavyExternalLibraryLazy 對象阻止Dagger(否則,在調用 provideHeavyExternalLibraryObservable() 方法調用的瞬間對象就會被創建)內部對HeavyExternalLibrary對象的初始化。
  • Observable.create(...) 代碼 - 它將在每次這個Observable被訂閱時通過調用 heavyExternalLibraryLazy.get() 返回 heavyExternalLibrary 對象。
  • .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); - 默認情況下RxJava代碼會在Observable被創建的線程中執行。這就是為什么我們要把執行移動到后臺線程(這里的 Schedulers.io() ),然后在主線程中( AndroidSchedulers.mainThread() )觀察結果。

我們的Observable像圖表中其它對象一樣被注入,但是 heavyExternalLibrary 對象本身將會延遲一點才可用:

public class SplashActivity {

@Inject
Observable<HeavyExternalLibrary> heavyExternalLibraryObservable;

//This will be injected asynchronously
HeavyExternalLibrary heavyExternalLibrary; 

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate();
    //...
    heavyExternalLibraryObservable.subscribe(new SimpleObserver<HeavyExternalLibrary>() {
        @Override
        public void onNext(HeavyExternalLibrary heavyExternalLibrary) {
            //Our dependency will be available from this moment
            SplashActivity.this.heavyExternalLibrary = heavyExternalLibrary;
        }
    });
}

}</code></pre>

異步新實例的注入

上面的代碼展示了怎么去注入單例的對象。那如果我們想異步注入新的實例呢?

確認我們的對象不再使用了@Singleton注解 :

@Provides
HeavyExternalLibrary provideHeavyExternalLibrary() {
    HeavyExternalLibrary heavyExternalLibrary = new HeavyExternalLibrary();
    heavyExternalLibrary.init(); //This method takes about 500ms
    return heavyExternalLibrary;
}

我們 Observable<HeavyExternalLibrary> provider方法也會有一點改變。我們不能使用 Lazy<HeavyExternalLibrary> 因為它只會在第一次調用 get() 方法的時候才會創建新的實例。

這里是更新后的代碼:

@Singleton
@Provides
Observable<HeavyExternalLibrary> provideHeavyExternalLibraryObservable(final Provider<HeavyExternalLibrary> heavyExternalLibraryProvider) {
    return Observable.create(new Observable.OnSubscribe<HeavyExternalLibrary>() {
        @Override
        public void call(Subscriber<? super HeavyExternalLibrary> subscriber) {
            subscriber.onNext(heavyExternalLibraryProvider.get());
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}

我們的 Observable<HeavyExternalLibrary> 可以是一個單例,,但是每一次我們去調用它的subscribe()方法的時候,我們將會在onNext()方法中得到一個新的 HeavyExternalLibrary 實例:

heavyExternalLibraryObservable.subscribe(new SimpleObserver<HeavyExternalLibrary>() {
    @Override
    public void onNext(HeavyExternalLibrary heavyExternalLibrary) {
        //New instance of HeavyExternalLibrary
    }
});

完全的異步注入

還有另一個方法是用RxJava在Dagger 2中進行異步注入。我們可以使用Observable簡單封裝整個注入過程。

我們注入的執行是這樣的(代碼摘自 GithubClient 項目):

public class SplashActivity extends BaseActivity {

@Inject
SplashActivityPresenter presenter;
@Inject
AnalyticsManager analyticsManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

//This method is called in super.onCreate() method
@Override
protected void setupActivityComponent() {
    final SplashActivityComponent splashActivityComponent = GithubClientApplication.get(SplashActivity.this)
            .getAppComponent()
            .plus(new SplashActivityModule(SplashActivity.this));
    splashActivityComponent.inject(SplashActivity.this);
}

}</code></pre>

要讓它變成異步我們只需要使用Observable封裝 setupActivityComponent() 方法:

@Override
protected void setupActivityComponent() {
    Observable.create(new Observable.OnSubscribe<Object>() {
        @Override
        public void call(Subscriber<? super Object> subscriber) {
            final SplashActivityComponent splashActivityComponent = GithubClientApplication.get(SplashActivity.this)
                    .getAppComponent()
                    .plus(new SplashActivityModule(SplashActivity.this));
            splashActivityComponent.inject(SplashActivity.this);
            subscriber.onCompleted();
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new SimpleObserver<Object>() {
                @Override
                public void onCompleted() {
                    //Here is the moment when injection is done.
                    analyticsManager.logScreenView(getClass().getName());
                    presenter.callAnyMethod();
                }
            });
}

正如注釋,所有 @Inject 注解了的對象將被未來某一時刻注入。在返回注入過程是異步的并且不會對主線程有很大的影響。

當然創建 Observable 對象和額外 subscribeOn() 線程并不是完全免費的 - 它將會花費一點時間。這類似于 Producers 代碼所產生的影響。

 

 

來自:http://www.cnblogs.com/tiantianbyconan/p/6236646.html

 

 本文由用戶 uvqr6246 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!