O RXJava é uma implementação Java VM de extensões reativas: uma biblioteca para compor programas assíncronos e baseados em eventos usando sequências observáveis.
Ele estende o padrão do observador para suportar sequências de dados/eventos e adiciona operadores que permitem compor sequências declarativamente ao abstrair preocupações sobre coisas como rosqueamento de baixo nível, sincronização, segurança de roscas e estruturas de dados simultâneas.
Saiba mais sobre o RXJava em geral na casa do wiki.
Leia o que é diferente no 3.0 para obter detalhes sobre as alterações e informações de migração ao atualizar a partir de 2.x.
A versão 2.x é de fim de vida em 28 de fevereiro de 2021 . Nenhum desenvolvimento adicional, suporte, manutenção, PRs e atualizações acontecerá. O javadoc da última versão, 2.2.21 , permanecerá acessível.
A versão 1.x é de fim de vida em 31 de março de 2018 . Nenhum desenvolvimento adicional, suporte, manutenção, PRs e atualizações acontecerá. O javadoc da última versão, 1.3.8 , permanecerá acessível.
O primeiro passo é incluir o RXJava 3 em seu projeto, por exemplo, como uma dependência de compilação gradle:
implementation " io.reactivex.rxjava3:rxjava:3.x.y "
(Substitua x
e y
pelos números mais recentes da versão :)
O segundo é escrever o programa Hello World :
package rxjava . examples ;
import io . reactivex . rxjava3 . core .*;
public class HelloWorld {
public static void main ( String [] args ) {
Flowable . just ( "Hello world" ). subscribe ( System . out :: println );
}
}
Observe que os componentes rxjava 3 agora vivem com io.reactivex.rxjava3
e as classes e interfaces base vivem sob io.reactivex.rxjava3.core
.
O RXJava 3 apresenta várias classes base que você pode descobrir os operadores em:
io.reactivex.rxjava3.core.Flowable
: 0..n flui, suportando streams reativos e backpressureio.reactivex.rxjava3.core.Observable
: 0..n fluxos, sem contrapressão,io.reactivex.rxjava3.core.Single
: um fluxo de exatamente 1 item ou um erro,io.reactivex.rxjava3.core.Completable
: um fluxo sem itens, mas apenas um sinal de conclusão ou erro,io.reactivex.rxjava3.core.Maybe
: um fluxo sem itens, exatamente um item ou um erro.Os fluxos de dados em rxjava consistem em uma fonte, zero ou mais etapas intermediárias, seguidas por um consumidor de dados ou etapa do combinador (onde a etapa é responsável por consumir o fluxo de dados por alguns meios):
source . operator1 (). operator2 (). operator3 (). subscribe ( consumer );
source . flatMap ( value -> source . operator1 (). operator2 (). operator3 ());
Aqui, se nos imaginarmos no operator2
, olhando para a esquerda em direção à fonte é chamado de Upstream . Olhando para a direita em direção ao assinante/consumidor é chamado de jusante . Isso geralmente é mais aparente quando cada elemento é escrito em uma linha separada:
source
. operator1 ()
. operator2 ()
. operator3 ()
. subscribe ( consumer )
Na documentação, emissão , emissão, emissões , item , sinal , dados e mensagens de Rxjava são considerados sinônimos e representam o objeto que viaja ao longo do fluxo de dados.
Quando o fluxo de dados é executado através de etapas assíncronas, cada etapa pode executar coisas diferentes com velocidade diferente. Para evitar sobrecarregar essas etapas, que geralmente se manifestariam como aumento do uso da memória devido ao buffer temporário ou à necessidade de pular/soltar dados, é aplicada a chamada contrapressão, que é uma forma de controle de fluxo em que as etapas podem expressar quantos itens Eles estão prontos para processar. Isso permite restringir o uso de memória dos fluxos de dados em situações em que geralmente não há como uma etapa saber quantos itens o upstream enviará para ele.
Em Rxjava, a classe Flowable
dedicada é designada para suportar a contrapressão e Observable
é dedicado às operações não apoiadas (sequências curtas, interações GUI etc.). Os outros tipos, Single
, Maybe
e Completable
não suportam a contrapressão nem deveriam; Sempre há espaço para armazenar um item temporariamente.
A preparação dos fluxos de dados aplicando vários operadores intermediários ocorre no chamado tempo de montagem :
Flowable < Integer > flow = Flowable . range ( 1 , 5 )
. map ( v -> v * v )
. filter ( v -> v % 3 == 0 )
;
Neste ponto, os dados ainda não estão fluindo e nenhum efeito colateral está acontecendo.
Este é um estado temporário quando subscribe()
é chamado em um fluxo que estabelece a cadeia de etapas de processamento internamente:
flow . subscribe ( System . out :: println )
É quando os efeitos colaterais da assinatura são acionados (consulte doOnSubscribe
). Algumas fontes bloqueiam ou começam a emitir itens imediatamente neste estado.
Este é o estado em que os fluxos estão emitindo ativamente itens, erros ou sinais de conclusão:
Observable . create ( emitter -> {
while (! emitter . isDisposed ()) {
long time = System . currentTimeMillis ();
emitter . onNext ( time );
if ( time % 2 != 0 ) {
emitter . onError ( new IllegalStateException ( "Odd millisecond!" ));
break ;
}
}
})
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Praticamente, é quando o corpo do exemplo dado acima é executado.
Um dos casos de uso comum para o RXJava é executar algum computação, solicitação de rede em um thread de segundo plano e mostrar os resultados (ou erro) no thread da interface do usuário:
import io . reactivex . rxjava3 . schedulers . Schedulers ;
Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
})
. subscribeOn ( Schedulers . io ())
. observeOn ( Schedulers . single ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 ); // <--- wait for the flow to finish
Esse estilo de métodos de encadeamento é chamado de API fluente que se assemelha ao padrão do construtor . No entanto, os tipos reativos de Rxjava são imutáveis; Cada uma das chamadas de método retorna um novo Flowable
com um comportamento adicional. Para ilustrar, o exemplo pode ser reescrito da seguinte maneira:
Flowable < String > source = Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
});
Flowable < String > runBackground = source . subscribeOn ( Schedulers . io ());
Flowable < String > showForeground = runBackground . observeOn ( Schedulers . single ());
showForeground . subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 );
Normalmente, você pode mover cálculos ou bloquear o IO para algum outro thread via subscribeOn
. Depois que os dados estiverem prontos, você pode garantir que eles sejam processados em primeiro plano ou thread GUI via observeOn
.
Os operadores de rxjava não funcionam diretamente com Thread
ou ExecutorService
, mas com os chamados Scheduler
que abstraem fontes de simultaneidade por trás de uma API uniforme. O RXJava 3 apresenta vários agendadores padrão acessíveis via classe de utilitário Schedulers
.
Schedulers.computation()
: Execute o trabalho intensivo em computação em um número fixo de threads dedicados em segundo plano. A maioria dos operadores assíncronos usa isso como seu Scheduler
padrão.Schedulers.io()
: Execute operações de E/S de E/O em um conjunto de threads em mudança dinamicamente.Schedulers.single()
: Execute o trabalho em um único thread de maneira seqüencial e FIFO.Schedulers.trampoline()
: Execute o trabalho de maneira seqüencial e FIFO em um dos threads participantes, geralmente para fins de teste. Eles estão disponíveis em todas as plataformas JVM, mas algumas plataformas específicas, como o Android, têm seus próprios Scheduler
típicos definidos: AndroidSchedulers.mainThread()
, SwingScheduler.instance()
ou JavaFXScheduler.platform()
.
Além disso, existe uma opção para envolver um Executor
existente (e seus subtipos como ExecutorService
) em um Scheduler
via Schedulers.from(Executor)
. Isso pode ser usado, por exemplo, para ter um pool de threads maior, mas ainda fixo (diferentemente computation()
e io()
respectivamente).
Thread.sleep(2000);
No final, não é por acaso. Em rxjava, o Scheduler
padrão é executado em threads Daemon, o que significa que uma vez que o thread principal java sai, todos eles são parados e os cálculos de fundo podem nunca acontecer. Dormir por algum tempo neste exemplo situações permite que você veja a saída do fluxo no console com o tempo de sobra.
Os fluxos em rxjava são seqüenciais de natureza dividida em estágios de processamento que podem ser executados simultaneamente entre si:
Flowable . range ( 1 , 10 )
. observeOn ( Schedulers . computation ())
. map ( v -> v * v )
. blockingSubscribe ( System . out :: println );
Este exemplo de fluxo quadrilha os números de 1 a 10 no Scheduler
de Computação e consome os resultados no encadeamento "principal" (mais precisamente, o encadeamento de chamadas do blockingSubscribe
). No entanto, o Lambda v -> v * v
não é paralelo para esse fluxo; Ele recebe os valores 1 a 10 no mesmo thread de computação um após o outro.
Processar os números 1 a 10 em paralelo é um pouco mais envolvido:
Flowable . range ( 1 , 10 )
. flatMap ( v ->
Flowable . just ( v )
. subscribeOn ( Schedulers . computation ())
. map ( w -> w * w )
)
. blockingSubscribe ( System . out :: println );
Praticamente, o paralelismo em rxjava significa executar fluxos independentes e fundir seus resultados de volta a um único fluxo. O operador flatMap
faz isso mapeando primeiro cada número de 1 a 10 em seu próprio indivíduo Flowable
, os executa e mescla os quadrados calculados.
Observe, no entanto, que o flatMap
não garante nenhum pedido e os itens dos fluxos internos podem acabar intercalados. Existem operadores alternativos:
concatMap
que mapeia e executa um fluxo interno de cada vez econcatMapEager
, que executa todos os fluxos internos "ao mesmo tempo", mas o fluxo de saída estará na ordem que esses fluxos internos foram criados. Alternativamente, o operador Flowable.parallel()
e o tipo ParallelFlowable
ajudam a alcançar o mesmo padrão de processamento paralelo:
Flowable . range ( 1 , 10 )
. parallel ()
. runOn ( Schedulers . computation ())
. map ( v -> v * v )
. sequential ()
. blockingSubscribe ( System . out :: println );
flatMap
é um operador poderoso e ajuda em muitas situações. Por exemplo, dado um serviço que retorna um Flowable
, gostaríamos de chamar outro serviço com valores emitidos pelo primeiro serviço:
Flowable < Inventory > inventorySource = warehouse . getInventoryAsync ();
inventorySource
. flatMap ( inventoryItem -> erp . getDemandAsync ( inventoryItem . getId ())
. map ( demand -> "Item " + inventoryItem . getName () + " has demand " + demand ))
. subscribe ( System . out :: println );
Às vezes, quando um item está disponível, gostaria de realizar alguns cálculos dependentes. Às vezes, isso é chamado de continuação e, dependendo do que deve acontecer e de quais tipos estão envolvidos, podem envolver vários operadores a serem realizados.
O cenário mais típico é ter um valor, invocar outro serviço, aguardar e continuar com seu resultado:
service . apiCall ()
. flatMap ( value -> service . anotherApiCall ( value ))
. flatMap ( next -> service . finalCall ( next ))
Muitas vezes, é o caso também que as seqüências posteriores exigiriam valores de mapeamentos anteriores. Isso pode ser conseguido movendo o flatMap
externo para as partes internas do flatMap
anterior, por exemplo:
service . apiCall ()
. flatMap ( value ->
service . anotherApiCall ( value )
. flatMap ( next -> service . finalCallBoth ( value , next ))
)
Aqui, o value
original estará disponível dentro do flatMap
interno, cortesia da Captura da Variável Lambda.
Em outros cenários, os resultados da primeira fonte/fluxo de dados são irrelevantes e gostaria de continuar com uma outra fonte quase independente. Aqui, flatMap
também funciona:
Observable continued = sourceObservable . flatMapSingle ( ignored -> someSingleSource )
continued . map ( v -> v . toString ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
No entanto, a continuação neste caso permanece Observable
em vez do Single
provável mais apropriado. (Isso é compreensível porque, da perspectiva do flatMapSingle
, sourceObservable
é uma fonte de vários valores e, portanto, o mapeamento também pode resultar em vários valores).
Freqüentemente, embora exista uma maneira que seja um pouco mais expressiva (e também menor sobrecarga) usando Completable
como mediador e seu operador andThen
para retomar com outra coisa:
sourceObservable
. ignoreElements () // returns Completable
. andThen ( someSingleSource )
. map ( v -> v . toString ())
A única dependência entre o sourceObservable
e o someSingleSource
é que o primeiro deve ser concluído normalmente para que o último seja consumido.
Às vezes, existe uma dependência implícita de dados entre a sequência anterior e a nova sequência que, por algum motivo, não estava fluindo através dos "canais regulares". Alguém estaria inclinado a escrever essas continuações da seguinte maneira:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . just ( count . get ()))
. subscribe ( System . out :: println );
Infelizmente, isso imprime 0
porque Single.just(count.get())
é avaliado no horário da montagem, quando o fluxo de dados ainda nem foi executado. Precisamos de algo que adia a avaliação desta Single
fonte até o tempo de execução , quando a fonte principal concluir:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . defer (() -> Single . just ( count . get ())))
. subscribe ( System . out :: println );
ou
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . fromCallable (() -> count . get ()))
. subscribe ( System . out :: println );
Às vezes, uma fonte ou serviço retorna um tipo diferente do fluxo que deve funcionar com ele. Por exemplo, no exemplo do inventário acima, getDemandAsync
pode retornar um Single<DemandRecord>
. Se o exemplo do código for inalterado, isso resultará em um erro de tempo de compilação (no entanto, geralmente com uma mensagem de erro enganosa sobre a falta de sobrecarga).
Nessas situações, geralmente existem duas opções para corrigir a transformação: 1) Converter para o tipo desejado ou 2) Encontre e use uma sobrecarga do operador específico que suporta o tipo diferente.
Cada classe base reativa apresenta operadores que podem executar essas conversões, incluindo as conversões de protocolo, para corresponder a algum outro tipo. A matriz a seguir mostra as opções de conversão disponíveis:
Fluente | Observável | Solteiro | Talvez | Completo | |
---|---|---|---|---|---|
Fluente | toObservable | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Observável | toFlowable 2 | first , firstOrError , single , singleOrError , last , lastOrError 1 | firstElement , singleElement , lastElement | ignoreElements | |
Solteiro | toFlowable 3 | toObservable | toMaybe | ignoreElement | |
Talvez | toFlowable 3 | toObservable | toSingle | ignoreElement | |
Completo | toFlowable | toObservable | toSingle | toMaybe |
1 : Ao transformar uma fonte de vários valores em uma fonte de valor único, deve-se decidir qual dos muitos valores de origem deve ser considerado como resultado.
2 : Transformar um Observable
em Flowable
requer uma decisão adicional: o que fazer com o potencial fluxo irrestrito da fonte Observable
? Existem várias estratégias disponíveis (como buffer, queda, mantendo as mais recentes) por meio do parâmetro BackpressureStrategy
ou por meio de operadores Flowable
padrão, como onBackpressureBuffer
, onBackpressureDrop
, onBackpressureLatest
que também permitem a personalização adicional do comportamento de contrapressão.
3 : Quando existe apenas (no máximo) um item de origem, não há problema com a contrapressão, pois ele sempre pode ser armazenado até que o jusante esteja pronto para consumir.
Muitos operadores usados frequentemente têm sobrecargas que podem lidar com os outros tipos. Eles geralmente são nomeados com o sufixo do tipo de destino:
Operador | Sobrecarga |
---|---|
flatMap | flatMapSingle , flatMapMaybe , flatMapCompletable , flatMapIterable |
concatMap | concatMapSingle , concatMapMaybe , concatMapCompletable , concatMapIterable |
switchMap | switchMapSingle , switchMapMaybe , switchMapCompletable |
A razão pela qual esses operadores têm um sufixo em vez de simplesmente ter o mesmo nome com a assinatura diferente é o apagamento do tipo. Java não considera assinaturas como operator(Function<T, Single<R>>)
e operator(Function<T, Maybe<R>>)
diferente (diferentemente de C#) e, devido ao apagamento, os dois operator
acabariam como métodos duplicados com a mesma assinatura.
Nomear na programação é uma das coisas mais difíceis, pois os nomes devem não demorar, expressivos, capturar e facilmente memoráveis. Infelizmente, o idioma de destino (e as convenções pré-existentes) podem não dar muita ajuda nesse sentido (palavras-chave inutilizáveis, apagamento de tipo, ambiguidades de tipo, etc.).
No RX.NET original, o operador que emite um único item e, em seguida, é chamado Return(T)
. Como a Convenção Java deve ter uma letra minúscula iniciar um nome de método, isso teria sido return(T)
que é uma palavra -chave em Java e, portanto, não está disponível. Portanto, o RXJava optou por nomear este operador just(T)
. A mesma limitação existe para o Switch
do operador, que teve que ser nomeado switchOnNext
. Outro exemplo é Catch
, que foi nomeado onErrorResumeNext
.
Muitos operadores que esperam que o usuário forneça alguma função que retorne um tipo reativo não pode ser sobrecarregado porque o tipo apagamento em torno de uma Function<T, X>
transforma essas assinaturas de método em duplicatas. Rxjava escolheu nomear esses operadores, anexando o tipo como sufixo também:
Flowable < R > flatMap ( Function <? super T , ? extends Publisher <? extends R >> mapper )
Flowable < R > flatMapMaybe ( Function <? super T , ? extends MaybeSource <? extends R >> mapper )
Embora certos operadores não tenham problemas com o apagamento do tipo, sua assinatura pode ser ambígua, especialmente se alguém usar Java 8 e Lambdas. Por exemplo, existem várias sobrecargas de concatWith
, tomando os vários outros tipos de base reativos como argumentos (para fornecer benefícios de conveniência e desempenho na implementação subjacente):
Flowable < T > concatWith ( Publisher <? extends T > other );
Flowable < T > concatWith ( SingleSource <? extends T > other );
Tanto Publisher
quanto SingleSource
aparecem como interfaces funcionais (tipos com um método abstrato) e podem incentivar os usuários a tentar fornecer uma expressão de lambda:
someSource . concatWith ( s -> Single . just ( 2 ))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Infelizmente, essa abordagem não funciona e o exemplo não imprime 2
. De fato, desde a versão 2.1.10, ele nem sequer compilou porque pelo menos quatro sobrecargas concatWith
sobrecarga e o compilador encontra o código acima ambíguo.
O usuário em tais situações provavelmente queria adiar algum computação até que a someSource
seja concluída, portanto, o operador não ambíguo correto deveria ter sido defer
:
someSource . concatWith ( Single . defer (() -> Single . just ( 2 )))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Às vezes, um sufixo é adicionado para evitar ambiguidades lógicas que possam compilar, mas produzem o tipo errado em um fluxo:
Flowable < T > merge ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > mergeArray ( Publisher <? extends T >... sources );
Isso também pode ser ambíguo quando os tipos de interface funcionais se envolvem como o argumento do tipo T
.
Os fluxos de dados podem falhar, momento em que o erro é emitido para o (s) consumidor (s). Às vezes, porém, várias fontes podem falhar nesse ponto que há uma escolha se espera ou não que todas elas concluam ou falhem. Para indicar esta oportunidade, muitos nomes de operadores são sufixados com as palavras de DelayError
(enquanto outros apresentam uma bandeira booleana de delayError
ou delayErrors
em uma de suas sobrecargas):
Flowable < T > concat ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > concatDelayError ( Publisher <? extends Publisher <? extends T >> sources );
Claro, os sufixos de vários tipos podem aparecer juntos:
Flowable < T > concatArrayEagerDelayError ( Publisher <? extends T >... sources );
As classes base podem ser consideradas pesadas devido ao grande número de métodos estáticos e de instância neles. O design de Rxjava 3 foi fortemente influenciado pela especificação de fluxos reativos; portanto, a biblioteca apresenta uma classe e uma interface de acordo com cada tipo reativo:
Tipo | Aula | Interface | Consumidor |
---|---|---|---|
0..n Backpressoused | Flowable | Publisher 1 | Subscriber |
0..n ilimitado | Observable | ObservableSource 2 | Observer |
1 elemento ou erro | Single | SingleSource | SingleObserver |
0..1 elemento ou erro | Maybe | MaybeSource | MaybeObserver |
0 elemento ou erro | Completable | CompletableSource | CompletableObserver |
1 O org.reactivestreams.Publisher
faz parte da biblioteca de fluxos reativos externos. É o principal tipo para interagir com outras bibliotecas reativas através de um mecanismo padronizado governado pela especificação de fluxos reativos.
2 A convenção de nomenclatura da interface era anexar Source
ao nome da classe semi-tradicional. Não há FlowableSource
, pois Publisher
é fornecido pela biblioteca reativa dos fluxos (e a subtipagem que também não teria ajudado na interoperação). Essas interfaces, no entanto, não são padrão no sentido da especificação de fluxos reativos e atualmente são apenas específicos de rxjava.
Por padrão, o próprio Rxjava não requer nenhuma configuração de proGuard/R8 e deve funcionar sem problemas. Infelizmente, a dependência dos fluxos reativos desde a versão 1.0.3 incorporou arquivos de classe Java 9 em seu frasco que podem causar avisos com o Proguard simples:
Warning: org.reactivestreams.FlowAdapters$FlowPublisherFromReactive: can't find superclass or interface java.util.concurrent.Flow$Publisher
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveProcessor: can't find superclass or interface java.util.concurrent.Flow$Processor
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber: can't find superclass or interface java.util.concurrent.Flow$Subscriber
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscription: can't find superclass or interface java.util.concurrent.Flow$Subscription
Warning: org.reactivestreams.FlowAdapters: can't find referenced class java.util.concurrent.Flow$Publisher
Recomenda -se que configure a seguinte entrada -dontwarn
no arquivo proguard-ruleset
do aplicativo:
-dontwarn java.util.concurrent.Flow*
Para o R8, o frasco rxjava inclui a META-INF/proguard/rxjava3.pro
com a mesma cláusula de não-canto e deve se aplicar automaticamente.
Para mais detalhes, consulte o wiki.
Versão 3.x está em desenvolvimento. As correções serão aplicadas às filiais 2.x e 3.x, mas novos recursos serão adicionados apenas ao 3.x.
Menores incrementos 3.x (como 3,1, 3.2, etc) ocorrerão quando ocorrem novas funcionalidades não triviais ou aprimoramentos significativos ou correções de bugs que podem ter mudanças comportamentais que podem afetar alguns casos de borda (como dependência do comportamento resultante de um bug). Um exemplo de um aprimoramento que classificaria, pois isso está adicionando suporte reativo de backpressure a um operador que anteriormente não o suportava. Isso deve ser compatível com versões anteriores, mas se comporta de maneira diferente.
Patch 3.xy incrementos (como 3.0.0 -> 3.0.1, 3.3.1 -> 3.3.2, etc) ocorrerão para correções de bugs e funcionalidade trivial (como adicionar uma sobrecarga de método). A nova funcionalidade marcada com uma anotação @Beta
ou @Experimental
também pode ser adicionada nas versões do patch para permitir uma rápida exploração e iteração de novas funcionalidades instáveis.
As APIs marcadas com a anotação @Beta
no nível de classe ou método estão sujeitas a alterações. Eles podem ser modificados de qualquer maneira, ou mesmo removidos a qualquer momento. Se o seu código for uma própria biblioteca (ou seja, ele é usado no caminho de classe dos usuários fora do seu controle), você não deve usar APIs beta, a menos que você as reembale (por exemplo, usando proguard, sombreamento, etc.).
As APIs marcadas com a anotação @Experimental
no nível de classe ou método quase certamente mudarão. Eles podem ser modificados de qualquer maneira, ou mesmo removidos a qualquer momento. Você não deve usá -los ou confiar neles em nenhum código de produção. Eles são puramente para permitir testes e feedback amplos.
As APIs marcadas com a anotação @Deprecated
no nível da classe ou método permanecerão suportadas até a próxima versão importante, mas é recomendável parar de usá -las.
Todo o código dentro dos io.reactivex.rxjava3.internal.*
Os pacotes são considerados API privados e não devem ser confiados. Pode mudar a qualquer momento.
http://reactivex.io/RxJava/3.x/javadoc/3.xy/
Binários e informações de dependência para maven, Ivy, Gradle e outros podem ser encontrados em http://search.maven.org.
Exemplo para Gradle:
implementation ' io.reactivex.rxjava3:rxjava:x.y.z '
E para Maven:
< dependency >
< groupId >io.reactivex.rxjava3</ groupId >
< artifactId >rxjava</ artifactId >
< version >x.y.z</ version >
</ dependency >
E para Ivy:
< dependency org = " io.reactivex.rxjava3 " name = " rxjava " rev = " x.y.z " />
Instantâneos após 1º de maio de 2021 estão disponíveis via https://oss.sonatype.org/content/repositories/snapshots/io/reactivex/rxjava3/rxjava/
repositories {
maven { url ' https://oss.sonatype.org/content/repositories/snapshots ' }
}
dependencies {
implementation ' io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT '
}
Os instantâneos javadoc estão disponíveis em http://reactivex.io/rxjava/3.x/javadoc/snapshot
Para construir:
$ git clone [email protected]:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
Mais detalhes sobre a construção podem ser encontrados na página de início do wiki.
Para bugs, perguntas e discussões, use os problemas do GitHub.
Copyright (c) 2016-present, RxJava Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.