zoukankan      html  css  js  c++  java
  • [Android]在Dagger 2中使用RxJava来进行异步注入(翻译)


    以下内容为原创,欢迎转载,转载请注明
    来自天天博客: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代码所产生的影响。

    感谢阅读!

    作者

    Miroslaw Stanek

    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的多绑定(翻译):__
  • 相关阅读:
    linux-CPU和核概念
    Nginx学习——location+proxy_pass左斜杠问题彻底弄清
    es概念一句话简介和注意点
    es-字段类型整理(6.x及以上)
    Nginx学习——location和rewrite
    Nginx学习——proxy_pass
    Nginx学习——简介及常用命令
    第三方接口调用异常补偿机制实现实例记录
    postgres日志爆盘处理方案-转自DBA汪x
    Xshell连接本地 Virtualbo Ubuntu
  • 原文地址:https://www.cnblogs.com/tiantianbyconan/p/6236646.html
Copyright © 2011-2022 走看看