以下內容為原創,歡迎轉載,轉載請注明
來自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6236646.html
在Dagger 2中使用RxJava來進行異步注入
原文:http://frogermcs.github.io/async-injection-in-dagger-2-with-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中使用它來進行異步注入。
異步@Singleton注入
這是我們繁重的對象:
@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;
}
});
}
}
異步新實例的注入
上面的代碼展示了怎么去注入單例的對象。那如果我們想異步注入新的實例呢?
確認我們的對象不再使用了@Singleton注解:
@Provides
HeavyExternalLibrary provideHeavyExternalLibrary() {
HeavyExternalLibrary heavyExternalLibrary = new HeavyExternalLibrary();
heavyExternalLibrary.init(); //This method takes about 500ms
return heavyExternalLibrary;
}
我們Observable<HeavyExternalLibrary> provider方法也會有一點改變。我們不能使用Lazy<HeavyExternalLibrary>因為它只會在第一次調用get()方法的時候(詳見Lazy文檔)才會創建新的實例。
這里是更新后的代碼:
@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);
}
}
要讓它變成異步我們只需要使用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代碼所產生的影響。
感謝閱讀!
作者
Head of Mobile Development @ Azimo
> __[Android]使用Dagger 2依賴注入 - DI介紹(翻譯):__
> __[Android]使用Dagger 2依賴注入 - API(翻譯):__
> __[Android]使用Dagger 2依賴注入 - 自定義Scope(翻譯):__
> __[Android]使用Dagger 2依賴注入 - 圖表創建的性能(翻譯):__
> __[Android]Dagger2Metrics - 測量DI圖表初始化的性能(翻譯):__
> __[Android]使用Dagger 2進行依賴注入 - Producers(翻譯):__
> __[Android]在Dagger 2中使用RxJava來進行異步注入(翻譯):__
> __[Android]使用Dagger 2來構建UserScope(翻譯):__
> __[Android]在Dagger 2中Activities和Subcomponents的多綁定(翻譯):__
