Android支持库中的CompletableFuture?

24

我今天正在将一个Android Studio项目迁移到Java 8、Android API Level 24和Jack工具链,以尝试新功能,特别是lambda表达式和CompletableFuture

不幸的是,CompletableFuture似乎仅从API Level 24开始提供(该项目的最低API Level为16)。

您知道有关将CompletableFuture引入Android支持库的计划吗?它看起来是解决Promises模式的好方法。


5
我不清楚谷歌对支持库的计划。但请注意,streamsupport 项目在其 streamsupport-cfuture 模块中也提供了 CompletableFuture 的后移版本。它可在 Android 和所有 Java 版本 >= 6 上运行(并经常进行测试)。请参阅 https://sourceforge.net/projects/streamsupport/。 - Stefan Zobel
@StefanZobel 如果你把你的评论作为我问题的答案,我会接受它作为最佳答案(因为它涵盖了Android)。 - Thomas Wana
谢谢。已经完成了。请看下面。 - Stefan Zobel
4个回答

32

streamsupport项目提供了streamsupport-cfuture组件中的CompletableFuture回溯,可用于Android开发,并支持所有设备。

可以使用以下任一方法:

dependencies {
    implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.4'
}

或者更现代的 android-retrofuture 分支,适用于 Android Studio >= 3.x

dependencies {
    implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.4'
}

如果您可以使用Android Studio 3.x及以上版本。

针对CompletableFuture的新Java 12异常处理方法已集成到1.7.0版本中,详情请参阅JDK-8211010

对于希望使用小型依赖库的用户,还提供了一个105 KiB的minifuture变体,它是一个经过“精简裁剪”的streamsupport-cfuture版本。

dependencies {
    implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
}

这个库没有依赖项,只提供了使用 CompletableFuture 所需的最小 API,没有任何其他内容(没有 Streams、公共 ForkJoinPool 等)。


6

streamsupport 库是 Stefan Zobel 在他的答案中提到的,这个库被特别为 Android Studio >=3.0 的 desugar 工具链进行了分叉,请查看 android-retrofuture


5

如果您不需要 CompletableFuture 的所有功能(例如结果链接),则可以使用此类(Kotlin):

/**
 * A backport of Java `CompletableFuture` which works with old Androids.
 */
class CompletableFutureCompat<V> : Future<V> {
    private sealed class Result<out V> {
        abstract val value: V
        class Ok<V>(override val value: V) : Result<V>()
        class Error(val e: Throwable) : Result<Nothing>() {
            override val value: Nothing
                get() = throw e
        }
        object Cancel : Result<Nothing>() {
            override val value: Nothing
                get() = throw CancellationException()
        }
    }

    /**
     * Offers the completion result for [result].
     *
     * If this queue is not empty, the future is completed.
     */
    private val completion = LinkedBlockingQueue<Result<V>>(1)
    /**
     * Holds the result of the computation. Takes the item from [completion] upon running and provides it as a result.
     */
    private val result = FutureTask<V> { completion.peek()!!.value }
    /**
     * If not already completed, causes invocations of [get]
     * and related methods to throw the given exception.
     *
     * @param ex the exception
     * @return `true` if this invocation caused this CompletableFuture
     * to transition to a completed state, else `false`
     */
    fun completeExceptionally(ex: Throwable): Boolean {
        val offered = completion.offer(Result.Error(ex))
        if (offered) {
            result.run()
        }
        return offered
    }

    /**
     * If not already completed, completes this CompletableFuture with
     * a [CancellationException].
     *
     * @param mayInterruptIfRunning this value has no effect in this
     * implementation because interrupts are not used to control
     * processing.
     *
     * @return `true` if this task is now cancelled
     */
    override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
        val offered = completion.offer(Result.Cancel)
        if (offered) {
            result.cancel(mayInterruptIfRunning)
        }
        return offered
    }

    /**
     * If not already completed, sets the value returned by [get] and related methods to the given value.
     *
     * @param value the result value
     * @return `true` if this invocation caused this CompletableFuture
     * to transition to a completed state, else `false`
     */
    fun complete(value: V): Boolean {
        val offered = completion.offer(Result.Ok(value))
        if (offered) {
            result.run()
        }
        return offered
    }

    override fun isDone(): Boolean = completion.isNotEmpty()

    override fun get(): V = result.get()

    override fun get(timeout: Long, unit: TimeUnit): V = result.get(timeout, unit)

    override fun isCancelled(): Boolean = completion.peek() == Result.Cancel
}

4

以下内容可能与您有关并且有用:Java:使用异步编程优化应用程序

本答案是关于在Java 7上使用上述库的CompletableFuture,而不是在Android上。但是,该库的文档表明它可以在Android上使用。我自己没有使用过。


3
这应该是一条评论。 - Eugen Pechanec
3
无法在Android上运行。仍需要API 24,这是最初的问题。 - Bisclavret
4
@Bisclavret 我在谈论的是streamsupport,它在那个答案中提到(具体是streamsupport-cfuture组件)。这个组件只需要API级别14或15,而且它运行得非常好。 - Sartorius

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接