How can I visualize the execution of RxJava graphs?
Suppose I have several complex chains of objects Single
, Maybe
and Observable
that do some tasks.
For example:
// Download, unzip and parse a release
public static Single<Release> fetchRelease(final Release release) {
final Path cachePath = getCachePath(release);
return download(release.url, cachePath, true).ignoreElements()
.andThen(hash(cachePath))
.flatMap(fileHash -> unzip(cachePath)
.andThen(parseFile(unzipTargetPath)));
}
These chains can run across multiple threads.
The problem is that I would like to make these tasks flow for the user without interfering with their logic where possible.
For example, the above task might show:
+-Fetching release 1.0... Done
+-Downloading https://www.example.com/v1.0.0.zip 100%
+-Hashing Library/Caches/Example/v1.0.0.zip... Done
+-Unpacking Library/Caches/Example/v1.0.0.zip
+-src.. Done
+-tests... Done
+-resources... Done
+-Parsing release... Done
Ideally, I would also like to show the hierarchy of tasks. This is currently only encoded in the Java call graph.
My modern thinking:
- Change each one
Single
toObservable
where the last item is the result and the others are progress updates. - Enter event classes for each step in the task.
I think this will make the code less readable and lead to a lot of boiler stove.
public final class DownloadProgress {
public final float progress;
// etc..
}
// etc...
public final class FetchReleaseProgress {
public final Variant<DownloadProgress, HashingProgress, UnpackProgress, ParseProgress> progress;
// etc...
}
What is the recommended approach?
source to share
you are on the right track, you can write a complete ui model that represents the ui events you are interested in. I will give your case here as an example
+-Fetching release 1.0... Done
+-Downloading https://www.example.com/v1.0.0.zip 100%
+-Hashing Library/Caches/Example/v1.0.0.zip... Done
+-Unpacking Library/Caches/Example/v1.0.0.zip
+-src.. Done
+-tests... Done
+-resources... Done
+-Parsing release... Done
and the model could be something like this:
final class DownloadUiModel {
private float progress;
private String hashing;
private String downloading;
private String unpacking;
private String done;
private DownloadUiModel(float progress, String hashing //..etc) {
}
//getters
//setters
}
then with Rxjava you can use the previous model like this:
download(release.url, cachePath, true)
.ignoreElements()
.map(response -> downloadUiModel.setDownloading(release.url))
.andThen(hash(cachePath))
.map(response -> downloadUiModel.setHashing(cachePath))
.flatMap(fileHash -> unzip(cachePath)
.andThen(parseFile(unzipTargetPath)))
.map(response -> downloadUiModel.setUnzipping(unzipTargetPath))
...
then when you sign up you can use this ui model to update you like
downloadObservable.subscribe(model ->
if(model.getProgress()!= 100){
Timber.d(model.getDownloading())
Timber.d(model.getHashing())
Timber.d(model.getUnpacking))
//...
}
the nice part of this way is that your ui logic is decoupled from your request logic and you can safely go to the main android theme.
source to share