How to check if RXJava finish or empty from queue - java

I have a function that loop the request using Retrofit and RXJava as below
for (i in month..12) {
if (Conn.connection(applicationContext)) {
Api.create().getDateInMonth("2019-$i-01")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<DateDataResponse> {
override fun onSubscribe(d: Disposable) {}
#SuppressLint("NewApi")
override fun onNext(dateDataResponse: DateDataResponse) {
Log.d("OnSuccess", "success")
}
#SuppressLint("NewApi")
override fun onError(e: Throwable) {
Log.d("onError", "error" + e.message)
}
override fun onComplete() {
Log.d("onComplete", "onComplete")
}
})
} else
Log.d("onError", "No Internet Connection")
}
}
so if some request error or success it will go on until the 12 request is finish. I want to detect if I already got all response from my request

If you turn this into a single chain, then you can use the onComplete() callback to verify that all your requests have finished. For example:
Observable.range(0, 12)
.filter { i-> Conn.connection(applicationContext) }
.flatMap { i -> Api.create().getDateInMonth("2019-$i-01") }
.subscribeOn(io())
.observeOn(mainThread())
.subscribe({ i-> }, { t-> }, {/*onComplete*/ })

Related

There is some error in my code. I want to add 1 to the firebase list but it keeps adding without stopping

`
override fun plusDown(key: String, downloads: Downloads, result: (UiState<String>) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
var size=0
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").addValueEventListener(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
size = snapshot.children.count()
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").child(size.toString()).setValue(
downloads
)
.addOnSuccessListener {
result.invoke(UiState.Success("SUCCES"))
Log.d("DOWNLOADCOUNT", size.toString())
}
.addOnFailureListener {
result.invoke(UiState.Failure(it.message))
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
`
and in the code below it does not add at all. I want to add only 1 time what do you advise
`
override fun plusDown(key: String, downloads: Downloads, result: (UiState<String>) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
var size=0
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").addValueEventListener(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
size = snapshot.children.count()
}
override fun onCancelled(error: DatabaseError) {
}
})
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").child(size.toString()).setValue(
downloads
)
.addOnSuccessListener {
result.invoke(UiState.Success("SUCCES"))
Log.d("DOWNLOADCOUNT", size.toString())
}
.addOnFailureListener {
result.invoke(UiState.Failure(it.message))
}
}
}
`
In code 1 There is some error in my code. I want to add 1 to the firebase list but it keeps adding without stopping
In code 2 and in the code below it does not add at all. I want to add only 1 time what do you advise
In your 1st code, change
addValueEventListener()
to
addListenerForSingleValueEvent()
Final Output
override fun plusDown(key: String, downloads: Downloads, result: (UiState<String>) -> Unit) {
CoroutineScope(Dispatchers.IO).launch {
var size=0
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").addListenerForSingleValueEvent(object :ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
size = snapshot.children.count()
myRef.getReference(FirebaseRealtimeDatabaseConstants.path_posts).child(key).child("downloads").child(size.toString()).setValue(
downloads
)
.addOnSuccessListener {
result.invoke(UiState.Success("SUCCES"))
Log.d("DOWNLOADCOUNT", size.toString())
}
.addOnFailureListener {
result.invoke(UiState.Failure(it.message))
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}

How consume multiple endpoints at same time using Kotlin Coroutine in a BackEnd Controller

Context: I found few tutorials explaining how consume mutilple endpoints from Kotlin at same time but they are based on Android and in my case it is a backend application. I have some experience using CompleteableFuture but I assume I should use Coroutine since it is a Kotlin and there is no Spring dependency.
Following some suggestions, I reached
#Singleton
class PersonEndpoint()
{
#Inject
lateinit var employeClient: EmployeClient
override suspend fun getPersonDetails(request: PersonRequest): PersonResponse {
var combinedResult: String
GlobalScope.launch {
val resultA: String
val resultB: String
val employeesA = async{ employeClient.getEmployeesA()}
val employeesB = async{ employeClient.getEmployeesB()}
try{
combinedResult = employeesA.await() + employeesB.await()
print(combinedResult)
} catch (ex: Exception) {
ex.printStackTrace()
}
// ISSUE 1
if I try add return over here it is not allowed.
I understand it is working how it is designed to work: GlobalScope is running in different thread
}
// ISSUE 2
if I try return combinedResult over here combinedResult isn't initialized.
I understand it is working how it is designed to work: GlobalScope is running in different thread and I can
debug and see that return over here executes earlier than employeesA.await = employeesB.await
}
So, how can I execute combinedResult = employeesA.await() + employeesB.await() before returning to the client?
*** Edited after Denis/ answer
#Singleton
class CustomerEndpoint(){
fun serve(): Collection<Int> {
return runBlocking {
async {
getItemDouble(1)
}
async {
getItemTriple(1)
}
}.map { it.await() }
}
suspend fun getItemDouble(i: Int): Int {
delay(1000)
return i * 2
}
suspend fun getItemTriple(i: Int): Int {
delay(1000)
return i * 3
}
override suspend fun getPersonDetails(request: PersonRequest): PersonResponse {
val result = serve()
println("Got result $result")
...
}
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis
fun main() {
val durationMs = measureTimeMillis {
val result = serve()
println("Got result $result")
}
println("The processing is done in $durationMs ms")
}
fun serve(): Collection<Int> {
return runBlocking {
(1..2).map {
async {
getItem(it)
}
}.map { it.await() }
}
}
suspend fun getItem(i: Int): Int {
delay(1000) // Emulate item retrieval work
return i * 2
}
Note that here we have two nested calls - getItem(1) and getItem(2). We can see that they are executed in parallel as overall running time is ~1 second.
Edited in August 05th 2021
private suspend fun myMethod(): List<Any> {
return runBlocking {
listOf(
async { method1() },
async { method2() }
).map { it.await() }
}
}
method1 and method2 are methods calling different endpoints.

Start obserable chain from Single.onErrorResumeNext in Rxjava2

loadSingle return Single object, if it fails I want to call getObservable(rsList) which return Observable.
I am trying with onErrorResumeNext but it needs Single object.
How can I call getObservable(rsList) on failure of loadSingle() ?
Thanks in advance!!
repo.loadSingle()
.subscribeOn(Schedulers.io())
.onErrorResumeNext {
repo.getObservable(rsList)
}
.flatMapObservable {
if (it != null && it.status == Status.SUCCESS) {
upRsList(it.data)
}
repo.getObservable(rsList)
}
({ //observable success
}, {
//observable error
})
Api interface
interface HomeApi{
fun getSingel():Single<List<String>>
fun getObservable():Observable<HomeResponse>
}
Dependencies
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.6.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.2")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.6.2")
implementation "io.reactivex.rxjava3:rxjava:3.0.4"
implementation "io.reactivex.rxjava3:rxkotlin:3.0.0"
Required classes
internal interface Repo {
fun loadSingle(): Single<Result<List<String>>>
fun getObservable(list: List<String>): Observable<String>
}
internal class RepoImpl : Repo {
override fun loadSingle(): Single<Result<List<String>>> {
return Single.error(RuntimeException("fail"))
}
override fun getObservable(list: List<String>): Observable<String> {
if (list === emptyList<String>()) {
return Observable.just("42")
}
return Observable.just("success")
}
}
internal sealed class Result<T> {
data class Success<T>(val value: T) : Result<T>()
data class Failure<T>(private val failure: Throwable) : Result<T>()
}
Test
Wrap the error via #onErrorReturn into a default value, and handle the result accordingly.
class So64751341 {
#Test
fun `64751341`() {
val repo: Repo = RepoImpl()
val testScheduler = TestScheduler()
val flatMapObservable = repo.loadSingle()
.subscribeOn(testScheduler)
.onErrorReturn { failure -> Result.Failure(failure) }
.flatMapObservable { result ->
when (result) {
is Result.Success -> repo.getObservable(result.value)
is Result.Failure -> repo.getObservable(emptyList())
}
}
val test = flatMapObservable.test()
testScheduler.triggerActions()
test // return default value 42 onError
.assertValue("42")
}
}
Repo#loadSingle() throws exception synchronously
internal class RepoExceptionImpl : Repo {
override fun loadSingle(): Single<Result<List<String>>> {
throw java.lang.RuntimeException("whatever")
}
override fun getObservable(list: List<String>): Observable<String> {
if (list === emptyList<String>()) {
return Observable.just("42")
}
return Observable.just("success")
}
}
Test
Repo#loadSingle must be wrapped with Single#defer. Single#defer will catch the exception and emit it as #onError to the subscriber, which in turn will be handled by #onErrorReturn
#Test
fun `64751341_exception`() {
val repo: Repo = RepoExceptionImpl()
val testScheduler = TestScheduler()
val flatMapObservable = Single.defer {
repo.loadSingle()
}
.subscribeOn(testScheduler)
.onErrorReturn { failure -> Result.Failure(failure) }
.flatMapObservable { result ->
when (result) {
is Result.Success -> repo.getObservable(result.value)
is Result.Failure -> repo.getObservable(emptyList())
}
}
val test = flatMapObservable.test()
testScheduler.triggerActions()
test // return default value 42 onError
.assertValue("42")
}

Android + RxJava + For Loop + Not executing all the requests

Caller Of the method,
for (String name : controllerToPartitionModels.keySet())
{
List<PartitionModel> partitionsList = controllerToPartitionModels.get(name);
refreshPartition(partitionsList,false);
}
Method
private void refreshPartition(List<PartitionModel> partitionModels, boolean isSyncAll) {
ITModule.getITService()
.refreshPartitionStatus(new ArrayList<>(partitionModels), isSyncAll)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Action() {
#Override
public void run() throws Exception {
Logger.get().d(ATTActionManager.this, "Refreshing request sent successfully for list of size : " + partitionModels.size());
}
}, (#NonNull Throwable throwable) -> {
Logger.get().d(ATTActionManager.this, "Error on Refresh request");
});
}
Problem
If there are 2 requests that has to be sent, I sometime see only one request being sent. Meaning, even though for loop is executing twice for 2 request(HTTP), I see only one request is being sent to the server.
What is that i am doing wrong here?
Rxjava version in use : 2.2.19
You can merge the above 2 methods to solve your problem by using flatMapIterable.
Merged Solution:
private void refreshPartition(Map<String, ?> controllerToPartitionModels) {
Observable.just(controllerToPartitionModels)
.map(controllerToPartitionModels -> controllerToPartitionModels.keySet())
.flatMapIterable((Function<Set<String>, Iterable<String>>) name -> name)
.map(name -> {
boolean isSyncAll = false; // You can customise as per requirement
return new Pair<List<PartitionModel>, Boolean>(controllerToPartitionModels.get(name), isSyncAll)
})
.flatMap((Function<Pair<List<PartitionModel>, Boolean>, ObservableSource<?>>) pair -> {
boolean isSyncAll = pair.first;
List<PartitionModel> partitionModels = pair.second;
return ITModule.getITService()
.refreshPartitionStatus(new ArrayList<>(partitionModels), isSyncAll)
}
)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Action() {
#Override
public void run() throws Exception {
Logger.get().d(ATTActionManager.this, "Refreshing request sent successfully for list of size : " + partitionModels.size());
}
}, (#NonNull Throwable throwable) -> {
Logger.get().d(ATTActionManager.this, "Error on Refresh request");
});
}
*Kindly replace ? with the valid object type.

Listen for Server response using Scarlet

so I have recently used scarlet WebSocket to successfully send data to my server online but the issue is that I am supposed to get a response from the server but am not getting anything.
below is my code:
class MainActivity : AppCompatActivity() {
#SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val socketInit = ServerClass(application)
socketInit.socket.observeWebSocketEvent()
.filter { it is WebSocket.Event.OnConnectionOpened<*> }
.subscribe({
val data = "{ \"lat\": 40.5555555555, \"lng\": 37.55564555554545, \"userId\": 2}"
val send = LocationAction(data =data)
socketInit.socket.subscribe(send)
Log.d("TAG_SUB",send.toString())
},{
Log.e("TAG", "Error while observing socket ${it.cause}")
})
socketInit.socket.observeTicker().subscribe({
idText.text =it
Log.d("TAG", "Observed: $it")
},
{
Log.e("TAG", "Error while observing ticker ${it.cause}")
})
}
}
here is my interface
interface SocketService {
#Receive
fun observeWebSocketEvent(): Flowable<WebSocket.Event>
#Send
fun subscribe(action: LocationAction)
#Receive
fun observeTicker(): Flowable<String>
}
this class bellow hold my scarlet implementation and my socket url
class ServerClass(application: Application): MainApplication() {
private val lifecycle = AndroidLifecycle.ofApplicationForeground(application = application)
private val backoffStrategy = ExponentialWithJitterBackoffStrategy(5000, 5000)
private val okHttpClient = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build()
val socket = Scarlet.Builder()
.webSocketFactory(okHttpClient.newWebSocketFactory("https://staging.kross.app/api/v1/notification/update"))
.addMessageAdapterFactory(MoshiMessageAdapter.Factory())
.addStreamAdapterFactory(RxJava2StreamAdapterFactory())
.backoffStrategy(backoffStrategy)
.lifecycle(lifecycle)
.build()
.create<SocketService>()
}
The observeTicker function should be where I listen for my response from the server but nothing is happening. Please I need help
I was experiencing the same problem, until I found a way to catch the messages coming from the socket.
I'm catching the messages this way:
socketInit.socket.observeWebSocketEvent()
.subscribe {
when (it) {
is WebSocketEvent.OnConnectionOpened -> {
//I do the Subscription Here the 1st message to the webserver
}
is WebSocketEvent.OnConnectionClosing -> {
//Connection Closing
}
is WebSocketEvent.OnConnectionFailed -> {
//If connection fails
}
is WebSocketEvent.OnMessageReceived -> {
//I'm doing it here!! If you parse the it.message.toString()
//You can transform the response into a JSON Object like this
val x : Response = Gson().fromJson(it.message.toString(), Response::class.java)
}
I hope this will help you

Categories