Debugging RxJava on Android
2015-11-13 17:44
691 查看
Skip
to content
About me
Debugging is the process of finding and resolving bugs or defects that prevent correct operation of computer software (Wikipedia).
Nowadays debugging is not an easy task, specially with all the complexity around current systems:Android is not an exception to this rule and
since we are dealing with asynchronous executions, that becomes way harder.
As you might know, at @SoundCloud,
we are heavily using RxJava as one of our
core components for Android Development, so in this article I am gonna walk you through the way we debug RxObservables and Subscribers.
Käppler talk at GOTO Conference (if you haven’t yet, I strongly recommend it), you may have noticed that he talks about someone called Gandalf (minute
41:15). All right, I have to say that in the beginning, Gandalf
was my failed attempt to create an Aspect Oriented Library for Android, fortunately after working hard and receiving useful feedback, it became an Android
Development Kit we use at @SoundCloud.
However, I wanted to have something smaller that solves only one problem, so I decided to extractRxJava Logging
specifics that I have been working on, and give life to Frodo.
Frodo is no more than an Android Library for Logging RxJava Observables
and Subscribers (for now), let’s say Gandalf’s little son or brother. It was actually inspired by Jake
Wharton’s Hugo Library.
Debugging is a cross cutting concern and we know how frustrating and painful could be. Additionally, many times you have to write
code (that is not part of your business logic) in order todebug stuff, which make things even more complicated, specially when it comes to asynchronous
code execution.
Frodo was born to achieve this and avoid writing code for debugging RxJava objects. It is based on Java Annotations and relies on a Gradle Plugin that
detects when the Debug build type of your application is compiled, and weaves code, which is gonna print RxJava Objects logging informationon the android logcat output. For instance, it
is safe to keep Frodo annotations in your codebaseeven when you are generating Release versions of your Android App. So now, let’s get our hands dirty and have a taste of it.
Plugin to our Android Project like this:
build.gradle
Java
As you can see, we add “com.fernandocejas.frodo:frodo-plugin:0.8.1” to the classpath and afterwards we apply the plugin ‘com.fernandocejas.frodo’.
That should be enough to have access to the Java annotations provided by the Library.
Then we subscribe to our sample observable:
MyClass.java
Java
When compiling and running our application, this is the information we are gonna see on the logcat:LogcatShell
Basically this means that we subscribed to an Observable returned by the list() method in ObservableSample class. Then we get information
about the emitted items, schedulers and events triggered by the annotated Observable.
To put an example, let’s create a RxJava dummy Subscriber and annotate it with @RxLogSubscriber.
MySubscriberBackpressure.java
Java
Forget about the backpressure name of this Subscriber for now, since this topic deserves a whole article. Just know that this Subscriber will only request 16 elements and it is gonna do nothing with the items it receives on the onNext() method. Even though that, we still wanna see what is going on when it subscribes to any Observable which emits Integer values:ObservableSample.javaJava
Here is when we subscribe to our SampleObservable:
MyClass.java
Java
Again when we compile and run our application, this is what we get from the logcat output:LogcatShell
Information here includes each of the items received, number of elements, schedulers, execution time and events triggered.
As you can see this information is useful in cases of backpressure,
or to see in which thread the items are being emitted or when we wanna se if our Subscriber has subscribed successfully,
thus avoiding memory leaks for example.
can check an article I wrote last year which includes an example with the same approach I am using for Frodo.
You
can also look into a presentation I prepared as an introduction for both AOP
and the Library or even better, dive into the source code.
Actually, one of the main reasons why it was open source, was to receive feedback/input from the community in order to improve it,
make it better and more useful. I have to say that I’m very excited and I have already used it in 3 different projects without many problems (check the known issues section below for more information). Of
course pull requests are very welcome too.
on a Gradle Plugin (as explained earlier) to detect Android Debug build variant and weave code, if
you make use of Android Library Projects,when you build your Application (even the debug build type), the official Android Gradle Plugin will always generate release
versions of all the Android Library projects included in your solution, thus,this stops Frodo from injecting generated code in annotated methods/classes. Of course this is not gonna
make your app to crash but you won’t see any output on the logcat. There is a workaround for this but be careful if you use it, since you do not wanna ship a release version of your
app with business objects being logged all over the place and exposing critical information.
Just add this flag to the android section in the build.gradle file of you Android Library Project:
build.gradle
Java
a sample app where you can see different use cases, such as Observable errors and other logging information. I
have also enabled Frodo in my Android
Clean Architecture repo if you wanna have a look into it.
The first version is out and you can find the repository of the project here:
https://github.com/android10/frodo
As always, any feedback is welcome. PRs as well if you wanna contribute. See you soon.
Aspect
Oriented Programming in Android.
AO
Programming and Frodo Presentation.
Matthias Käppler Talk at
GOTO Conference: Going Reactive.
Tagged as: android, androiddev, aop, asm, asmdex, aspect
oriented programming, aspectj, cglib, code
injection, development, javassits, programming, reactive, reactive
programming, weaving
Categorized in: Android, Aspect
Oriented Programming, Development, Java, Reactive
Programming
Posted on November
5, 2015 by fcejas
You must be logged
in to post a comment.
Architecting
Android…The evolution
Fernando Cejas © 2013 - fernandocejas.com
Search for:
Debugging RxJava on
Android
Architecting
Android…The evolution
Tasting Dagger 2 on
Android
RxJava
Observable tranformation: concatMap() vs flatMap()
Architecting
Android…The clean way?
November 2015
July 2015
April 2015
January 2015
September 2014
August 2014
April 2014
September 2013
Android
Aspect
Oriented Programming
Development
Java
Reactive
Programming
Software
Architecture
Testing
Log in
Entries RSS
Comments RSS
WordPress.org
to content
Fernando Cejas
About me
Debugging RxJava on
Android
Debugging is the process of finding and resolving bugs or defects that prevent correct operation of computer software (Wikipedia).Nowadays debugging is not an easy task, specially with all the complexity around current systems:Android is not an exception to this rule and
since we are dealing with asynchronous executions, that becomes way harder.
As you might know, at @SoundCloud,
we are heavily using RxJava as one of our
core components for Android Development, so in this article I am gonna walk you through the way we debug RxObservables and Subscribers.
Give a warm welcome to Frodo
Let me get started by introducing Frodo, but first, if you already watched MatthiasKäppler talk at GOTO Conference (if you haven’t yet, I strongly recommend it), you may have noticed that he talks about someone called Gandalf (minute
41:15). All right, I have to say that in the beginning, Gandalf
was my failed attempt to create an Aspect Oriented Library for Android, fortunately after working hard and receiving useful feedback, it became an Android
Development Kit we use at @SoundCloud.
However, I wanted to have something smaller that solves only one problem, so I decided to extractRxJava Logging
specifics that I have been working on, and give life to Frodo.
Frodo is no more than an Android Library for Logging RxJava Observables
and Subscribers (for now), let’s say Gandalf’s little son or brother. It was actually inspired by Jake
Wharton’s Hugo Library.
Debugging RxJava
First of all, I assume that you have basic knowledge about RxJava and its core components:Observables and Subscribers.Debugging is a cross cutting concern and we know how frustrating and painful could be. Additionally, many times you have to write
code (that is not part of your business logic) in order todebug stuff, which make things even more complicated, specially when it comes to asynchronous
code execution.
Frodo was born to achieve this and avoid writing code for debugging RxJava objects. It is based on Java Annotations and relies on a Gradle Plugin that
detects when the Debug build type of your application is compiled, and weaves code, which is gonna print RxJava Objects logging informationon the android logcat output. For instance, it
is safe to keep Frodo annotations in your codebaseeven when you are generating Release versions of your Android App. So now, let’s get our hands dirty and have a taste of it.
Using Frodo
To use Frodo the first thing we need to do is to simply apply a GradlePlugin to our Android Project like this:
build.gradle
Java
123456789101112 | buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' classpath "com.fernandocejas.frodo:frodo-plugin:0.8.1" }} apply plugin: 'com.android.application'apply plugin: 'com.fernandocejas.frodo' |
That should be enough to have access to the Java annotations provided by the Library.
Inspecting @RxLogObservable
The first core functionality of Frodo is to log RxJava Observables through @RxLogObservable Java annotation. Let’s say we have a method that returns an Observable which will emit a list of some sort of DummyClass:ObservableSample.javaJava1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class ObservableSample { @RxLogObservable public Observable<List<MyDummyClass>> list() { return Observable.just(buildDummyList()); } public List<MyDummyClass> buildDummyList() { return Arrays.asList(new MyDummyClass("Batman"), new MyDummyClass("Superman")); } public static final class MyDummyClass { private final String name; MyDummyClass(String name) { this.name = name; } @Override public String toString() { return "Name: " + name; } } } |
MyClass.java
Java
12345678910 | final ObservableSample observableSample = new ObservableSample();observableSample.list() .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<List<ObservableSample.MyDummyClass>>() { @Override public void call(List<ObservableSample.MyDummyClass> myDummyClasses) { toastMessage("onNext() List--> " + myDummyClasses.toString()); } }); |
1 2 3 4 5 6 | ObservableSample D Frodo => [@Observable :: @InClass -> ObservableSample :: @Method -> list()] D Frodo => [@Observable#list -> onSubscribe() :: @SubscribeOn -> RxNewThreadScheduler-3] D Frodo => [@Observable#list -> onNext() -> [Name: Batman, Name: Superman]] D Frodo => [@Observable#list -> onCompleted()] D Frodo => [@Observable#list -> onTerminate() :: @Emitted -> 1 element :: @Time -> 0 ms] D Frodo => [@Observable#list -> onUnsubscribe() :: @ObserveOn -> main] |
about the emitted items, schedulers and events triggered by the annotated Observable.
Inspecting @RxLogSubscriber
Let’s now explore what @RxLogSubscriber is capable of.To put an example, let’s create a RxJava dummy Subscriber and annotate it with @RxLogSubscriber.
MySubscriberBackpressure.java
Java
12345678910111213141516171819202122232425 | @RxLogSubscriberpublic class MySubscriberBackpressure extends Subscriber<Integer> { @Override public void onStart() { request(16); } @Override public void onNext(Integer value) { //empty } @Override public void onError(Throwable throwable) { //empty } @Override public void onCompleted() { if (!isUnsubscribed()) { unsubscribe(); } }} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class ObservableSample { public Observable<Integer> numbersBackpressure() { return Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { try { if (!subscriber.isUnsubscribed()) { for (int i = 1; i < 10000; i++) { subscriber.onNext(i); } subscriber.onCompleted(); } } catch (Exception e) { subscriber.onError(e); } } }); } } |
MyClass.java
Java
123456 | final ObservableSample observableSample = new ObservableSample();observableSample.numbersBackpressure() .onBackpressureDrop() .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new MySubscriberBackpressure()); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | SubscriberBackpressure D Frodo => [@Subscriber :: MySubscriberBackpressure -> onStart()] D Frodo => [@Subscriber :: MySubscriberBackpressure -> @Requested -> 40 elements] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 1 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 2 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 3 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 4 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 5 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 6 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 7 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 8 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 9 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 10 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 11 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 12 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 13 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 14 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 15 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onNext() -> 16 :: @ObserveOn -> main] D Frodo => [@Subscriber :: MySubscriberBackpressure -> onCompleted() :: @Received -> 16 elements :: @Time -> 3 ms] D Frodo => [@Subscriber :: MySubscriberBackpressure -> unSubscribe()] |
As you can see this information is useful in cases of backpressure,
or to see in which thread the items are being emitted or when we wanna se if our Subscriber has subscribed successfully,
thus avoiding memory leaks for example.
Frodo under the hood
In this article, I’m not gonna explain in details how the library internally works, however, if you are curious about it, youcan check an article I wrote last year which includes an example with the same approach I am using for Frodo.
You
can also look into a presentation I prepared as an introduction for both AOP
and the Library or even better, dive into the source code.
Disclaimer: Early stage
Frodo was just born and there is a long way ahead of it. It is still in a very early stage, so you might find issues or things to improve.Actually, one of the main reasons why it was open source, was to receive feedback/input from the community in order to improve it,
make it better and more useful. I have to say that I’m very excited and I have already used it in 3 different projects without many problems (check the known issues section below for more information). Of
course pull requests are very welcome too.
Known issues
So far, there is a well known issue: since Frodo relieson a Gradle Plugin (as explained earlier) to detect Android Debug build variant and weave code, if
you make use of Android Library Projects,when you build your Application (even the debug build type), the official Android Gradle Plugin will always generate release
versions of all the Android Library projects included in your solution, thus,this stops Frodo from injecting generated code in annotated methods/classes. Of course this is not gonna
make your app to crash but you won’t see any output on the logcat. There is a workaround for this but be careful if you use it, since you do not wanna ship a release version of your
app with business objects being logged all over the place and exposing critical information.
Just add this flag to the android section in the build.gradle file of you Android Library Project:
build.gradle
Java
1 2 3 | android { defaultPublishConfig "debug" } |
Frodo Example Application
The repository includesa sample app where you can see different use cases, such as Observable errors and other logging information. I
have also enabled Frodo in my Android
Clean Architecture repo if you wanna have a look into it.
Wrapping up
This is pretty much I have to offer in this article, and I hope you have found Frodo useful.The first version is out and you can find the repository of the project here:
https://github.com/android10/frodo
As always, any feedback is welcome. PRs as well if you wanna contribute. See you soon.
Useful links
Frodo Project website.Aspect
Oriented Programming in Android.
AO
Programming and Frodo Presentation.
Matthias Käppler Talk at
GOTO Conference: Going Reactive.
Tagged as: android, androiddev, aop, asm, asmdex, aspect
oriented programming, aspectj, cglib, code
injection, development, javassits, programming, reactive, reactive
programming, weaving
Categorized in: Android, Aspect
Oriented Programming, Development, Java, Reactive
Programming
Posted on November
5, 2015 by fcejas
Leave a Reply
You must be loggedin to post a comment.
Post navigation
ArchitectingAndroid…The evolution
Fernando Cejas © 2013 - fernandocejas.com
Search for:
Recent Posts
Debugging RxJava onAndroid
Architecting
Android…The evolution
Tasting Dagger 2 on
Android
RxJava
Observable tranformation: concatMap() vs flatMap()
Architecting
Android…The clean way?
Recent Comments
Archives
November 2015July 2015
April 2015
January 2015
September 2014
August 2014
April 2014
September 2013
Categories
AndroidAspect
Oriented Programming
Development
Java
Reactive
Programming
Software
Architecture
Testing
Meta
Log inEntries RSS
Comments RSS
WordPress.org
相关文章推荐
- Android基础入门教程——10.10 传感器专题(1)——相关介绍
- Activity与Fragment切换动画
- Android之zxing二维码生成于识别
- Android-Universal-Image-Loader最新框架解析
- 【Android学习笔记】Android中的进程和线程
- Android 打印小结
- Android属性动画LayoutTransition(布局容器动画)
- android四大组件之Service
- Activity全透明
- Android平台接入Facebook登录
- 欢迎使用CSDN-markdown编辑器
- 为android textview添加scrollbar
- Intent Resolving in Android M
- Android实现本地上传图片并设置为圆形头像
- Android 读取SD卡中的text文件内容
- 【Android学习笔记】Intent详解
- Android 调用js,传对象到js里面使用addJavascriptInterface错误总结
- Android自定义图片加载框架
- 获取Android设备电池电量状态
- android开发的一些网址