[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进行异步注入的文章。


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

img_f6f6cb6d1b74bcf6ef2fcde47349e234.png

感谢阅读!

作者

Miroslaw Stanek

Head of Mobile Development @ Azimo


[Android]使用Dagger 2依赖注入 - DI介绍(翻译):

http://www.cnblogs.com/tiantianbyconan/p/5092083.html


[Android]使用Dagger 2依赖注入 - API(翻译):

http://www.cnblogs.com/tiantianbyconan/p/5092525.html


[Android]使用Dagger 2依赖注入 - 自定义Scope(翻译):

http://www.cnblogs.com/tiantianbyconan/p/5095426.html


[Android]使用Dagger 2依赖注入 - 图表创建的性能(翻译):

http://www.cnblogs.com/tiantianbyconan/p/5098943.html


[Android]Dagger2Metrics - 测量DI图表初始化的性能(翻译):

http://www.cnblogs.com/tiantianbyconan/p/5193437.html


[Android]使用Dagger 2进行依赖注入 - Producers(翻译):

http://www.cnblogs.com/tiantianbyconan/p/6234811.html


[Android]在Dagger 2中使用RxJava来进行异步注入(翻译):

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


[Android]使用Dagger 2来构建UserScope(翻译):

http://www.cnblogs.com/tiantianbyconan/p/6237731.html


[Android]在Dagger 2中Activities和Subcomponents的多绑定(翻译):

http://www.cnblogs.com/tiantianbyconan/p/6266442.html

相关文章
|
Android开发 数据格式 JSON
【Android架构】基于MVP模式的Retrofit2+RXjava封装之常见问题(四)
先回顾下之前的 【Android架构】基于MVP模式的Retrofit2+RXjava封装(一)【Android架构】基于MVP模式的Retrofit2+RXjava封装之文件下载(二)【Android架构】基于MVP模式的Retrofit2+RXjava封装之文件上传(三) 今天要说的是使用Retrofit2和Okhttp 过程中遇到的一些问题。
1084 0
|
Android开发 流计算
【Android架构】基于MVP模式的Retrofit2+RXjava封装之文件下载(二)
上篇中我们介绍了基于MVP的Retrofit2+RXjava封装,还没有看的点击这里,这一篇我们来说说文件下载的实现。 首先,我们先在ApiServer定义好调用的接口 @GET Observable downloadFile(@Url St...
1377 0
|
Android开发
【Android架构】基于MVP模式的Retrofit2+RXjava封装之文件上传(三)
最近手头事比较多,抽个空把之前系列也补充一下。 先回顾下之前的 【Android架构】基于MVP模式的Retrofit2+RXjava封装(一)【Android架构】基于MVP模式的Retrofit2+RXjava封装之文件下载(二) 今天要说的是文件上传 1.
3429 0
|
Android开发
【Android架构】基于MVP模式的Retrofit2+RXjava封装(一)
#最近有个新项目要做,搭建框架的时候,顺便梳理了下MVP模式,特此记录,欢迎大家指正。 项目地址GitHub 一 、首先是依赖 compile 'com.
1330 0
|
6天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
5天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
18 5
|
3天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
5天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
16 3
|
7天前
|
存储 IDE 开发工具
探索Android开发之旅:从新手到专家
【10月更文挑战第26天】在这篇文章中,我们将一起踏上一段激动人心的旅程,探索如何在Android平台上从零开始,最终成为一名熟练的开发者。通过简单易懂的语言和实际代码示例,本文将引导你了解Android开发的基础知识、关键概念以及如何实现一个基本的应用程序。无论你是编程新手还是希望扩展你的技术栈,这篇文章都将为你提供价值和启发。让我们开始吧!