Recently, the news came that Android Studio 4 will support a so-called "desugaring" of Java 8 APIs (i.e., some kind of auto-backport for target devices not supporting newer API levels as I understand). This would allow RxJava 3 to increase the baseline support to Java 8 on its surface API:
Stream supportCollectors supportOptional supportCompletableFuture supportSome features won't be supported:
java.time.Duration: allocates, we'll stick to time+unitjava.util.function: these can't throw Throwables, overloads would create bloat and/or ambiguityThe main issue with Android's Java 8 support is timing related to the pledged release schedule of RxJava 3.x, end of December 2019. AGP 4 may not release for months, inclining us to:
The same issue is likely to arise with the next step, Java 9 support on Android. From our perspective, support for the Flow.* interfaces would be just enough as none of the other 9 features would work (VarHandles - field reflection anomalies?, Cleaner - portable?, Modules?). Beyond 9, the next major change to RxJava would have to come due to value types (no version ETA yet). Loom/Fibers is likely simply an API expansion, not a fundamental change.
Suggestions, ideas welcome.
Just some of my thoughts.
I'm not a fan of the 1st option, because literally nobody wins. People can still use RxJava 2 before AGP 4 comes out. I think the 3rd option makes a lot more sense than the 1st.
For Java 9 support, only supporting Flow.* interfaces to me doesn't justify requiring Java 9, as interoperating between the interfaces is pretty easy.
If I had to pick an option, I'd stick with Java 6. I've been using RxJava 2 with Java 8 on the server side, and not supporting Java 8 out-of-the-box does not feel like much of a hindrance, since the interop library is pretty nice and easy to use. Also, not requiring Java 8 is IMO one of the distinguishing features of RxJava vs Reactor Core.
I'm also okay with supporting Java 8 from the start and releasing on schedule. If RxJava 3 is set to support Java 8, it makes no sense to me to delay the initial release or to release it without Java 8 features.
In my opinion, if Java 6 is a must then go with RxJava2. The best option to me seems to be the third, although it means postponing some improvements that may come up gradually in the form of patches.
And maybe Java 11 would be a better choice than Java 9 in the future? Just thinking out loud...
And maybe Java 11 would be a better choice than Java 9 in the future? Just thinking out loud...
I think requiring a newer Java version only makes sense if that version has features that are beneficial to RxJava. For Java 8 it's Streams, CompletableFutures, etc. For Java 9 it's Flow.* and potentially Cleaner? I don't think Java 11 has anything worthwhile.
+1 for option 3
From Android's perspective, you do not need to wait for desguaring to ship to use the types mentioned.
Stream: Presumably this would only exist as a static factory for creating an Observable/Flowable from a Stream in which case this would only be callable on API 24+.Collector: This would exist as a blocking consumer member method on Observable/Flowable which would only be callable on API 24+CompletableFuture: Factory methods and conversion method for Completable and Single which would only be callable on API 24+Optional: Not sure what this would be used for. Factory method for Maybe? If so, would only be callable on API 24+TYPE_USE annotations: Have been removed by the build tooling for at least a year or two.As long as none of the critical path uses these types and they're only used as leaf sources created by factories or leaf converters implemented as operators the rest of the API will work fine and these types will only be usable on API 24+.
When desugaring does ship, these APIs will magically work on older APIs without any change necessary. There is no need to wait for it to launch.
As to Duration, while you shouldn't use it internally because it allocates, it's still _very_ useful for APIs that accept timeouts or intervals so that you can carry the scalar and unit as a single value and store it as a type-safe constant. Internally, RxJava can immediately convert it to millis or its preferred unit. This, also could still be used today provided it's done as overloads which immediately convert into long. Those APIs would only work on API 26+ until desugaring launches when they'd become magically available on older versions.
So, basically, I vote 3 as well.
As to
Duration, while you shouldn't use it internally because it allocates, it's still very useful for APIs that accept timeouts or intervals so that you can carry the scalar and unit as a single value and store it as a type-safe constant. Internally, RxJava can immediately convert it to millis or its preferred unit. This, also could still be used today provided it's done as overloads which immediately convert into long. Those APIs would only work on API 26+ until desugaring launches when they'd become magically available on older versions.
As an example, OkHttp does this:
+1 to everything Jake mentioned. It's quite standard to compile against Java 8 in Android projects these days since the original introduction of Desugar. Android's linter protects against usage of any Java 8 APIs that wouldn't be covered under desugar, so there's no danger for consumers either as long as they're just top-level conversion APIs like Jake described above.
What do you mean by "leaf"? The following API integrations would be possible with Java 8:
public static <T> Flowable<T> fromStream(Stream<T> stream);
public static <T> Flowable<T> fromCompletionStage(CompletionStage<T> cs);
public static <T> Flowable<T> fromOptional(Optional<T> option);
// -----
public Stream<T> blockingToStream();
public CompletionStage<T> firstElementStage();
public CompletionStage<T> firstOrErrorStage();
public CompletionStage<T> singleElementStage();
public CompletionStage<T> singleOrErrorStage();
public CompletionStage<T> lastElementStage();
public CompletionStage<T> lastOrErrorStage();
public <T, A, C, R> Single<R> collect(Collector<T, A, C, R> collector);
public <R> Flowable<R> mapOptional(Function<T, Optional<R>> mapper);
public <R> Flowable<R> flatMapStream(Function<T, Stream<R>> mapper);
So 3 static methods 10 instance methods with otherwise isolated implementations (existing operators wouldn't use Java 8 features such as Objects or Java 8 types, nor the backing implementations of these).
One risk is Java 8's Objects by the way, as a Java 8 compiler sometimes inserts it into the compiled output even though the source didn't mention it (example: #5966).
I'm pretty sure Objects is available on Java 7. Also, wasn't https://github.com/ReactiveX/RxJava/pull/5966 caused by error-prone?
Objects.requireNonNull has also been desugared automatically since AGP 3.0.
I have cobbled together a small library that uses Java 8 API and features.
I've created a basic Android Studio 3.5.2 project using it from maven local and kept modifying the compileSdkVersion, minSdkVersion and targetSdkVersion to 14, 24 and 29.
Stream, CompletionStage, Duration and Optional won't compileDuration won't compileAlso tried AS 4 canary 5
CompletableFuture gives IDE error (minSdk >= 24 required), the project deploys successfully but fails at runtime with missing class. CompletionStage interface gives no error but its methods do.What do you mean by "leaf"?
Having no internal callers. All of your listed examples above seem like they fit the bill. As long as these operators and factories are not used internally (unless by overloads/similar functionality), they'll simply be unused for people who cannot use those types due to the NewApi lint check.
If I try the library with a JavaVersion.VERSION_1_7 android project, not calling any of the JDK 8 APIs, I get the error
The dependency contains Java 8 bytecode. Please enable desugaring by adding the following to build [...]
requiring the compile options set to 1.8. Is such version leap on a project otherwise not using Java 8 dependencies or features going to be fine?
It is becoming common for libraries to do this nowadays, yes. Java 8 is ancient at this point, and the fact that the Android tooling has not made it the default is ridiculous. OkHttp did it 9 months ago and it's one of the most popular libraries on the platform: https://developer.squareup.com/blog/okhttp-3-13-requires-android-5/.
Okay. Let's upgrade to RxJava 8 baseline and release without delaying too much.
Progress tracked in #6776.
Most helpful comment
Okay. Let's upgrade to RxJava 8 baseline and release without delaying too much.