How to handle Exception in map() RxJava - android

I'm calling an API which throws 404 status code and due to that app gets crashed. The code snippet is mentioned below:
fun loadAndSavedata(
type: Type,
bookmark: String? = null,
): Single<MetaData> {
return loadFilesByType(type, bookmark)
.map { response ->
if (!response.isSuccessfulAndHasBody()) {
//This line gets pointed as cause
throw OfflineModeException(response)
}
response.body()!!
}
.flatMap { loadNextPages(it, type) }
}
The error, I receive in logcat is:
Process: com.example.app, PID: 23797
io.reactivex.rxjava3.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | com.com.example.app.models.OfflineModeException: HTTP 404
at io.reactivex.rxjava3.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.rxjava3.internal.operators.single.SingleZipArray$ZipCoordinator.innerError(SingleZipArray.java:139)
at io.reactivex.rxjava3.internal.operators.single.SingleZipArray$ZipSingleObserver.onError(SingleZipArray.java:175)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onError(SingleFlatMap.java:91)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onError(SingleFlatMap.java:91)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onError(SingleFlatMap.java:91)
at io.reactivex.rxjava3.internal.operators.single.SingleFlatMap$SingleFlatMapCallback.onError(SingleFlatMap.java:91)
at io.reactivex.rxjava3.internal.operators.single.SingleMap$MapSingleObserver.onError(SingleMap.java:70)
at io.reactivex.rxjava3.internal.operators.single.SingleMap$MapSingleObserver.onSuccess(SingleMap.java:61)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSingleSingle$SingleElementObserver.onComplete(ObservableSingleSingle.java:110)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onComplete(ObservableSubscribeOn.java:68)
at retrofit2.adapter.rxjava3.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:52)
at io.reactivex.rxjava3.core.Observable.subscribe(Observable.java:13095)
at io.reactivex.rxjava3.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:589)
at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
Caused by: com.com.example.app.models.OfflineModeException: HTTP 404
Can anyone please guide me how I can handle this error and avoid crash?

throw OfflineModeException(response)
// you are explicitly throwing exception on unsuccessful response. Remove this line or add a try catch block

You can not use throw directly because map function accept functional Interface Function<T,R>. In Function<T,R> abstract method is R apply(T t) so in apply function no throws present so you can not use throw keyword without try catch block
in map.

Related

How to make suspend function of a mock to throw a checked exception

Is there any way to get an exception response when calling suspended function?
Here is my solution but this is not working as I expected.
private fun mockServiceResponse() = service.stub {
onBlocking { loadMessages(Mockito.any() ?: createInstance()) }
.thenThrow(SocketException::class.java)
}
The test fails with the following error message.
Checked exception is invalid for this method!
Invalid: java.net.SocketException
org.mockito.exceptions.base.MockitoException:
will work if I replace thenThrow(SocketException::class.java)}
with thenAnswer { throw SocketException() }

Data retrieving from Database Crashes when in MVVM with the Error Could not Connect To Firestore

I am trying to call data from Firebase and map it to data class while using MVVM but Its showing me errors saying failed to Connect
The code of Repository Implementation:
override suspend fun uploaded_docs_retrival(): ArrayList<String> {
return try {
val result = Firebase.firestore.collection("users").whereEqualTo("UID", "84HMm1MJx8X8G33i7sxqUKQLzTn2").get()
.await()
result.first().toObject(docretreving::class.java).Docs
} catch (e: Exception) {
Log.e("TAG", "Failed to upload: ${e.message.orEmpty()}")
ArrayList()
}
}
Code of View Model:-
val livedata : MutableLiveData<ArrayList<String>> by lazy
MutableLiveData<ArrayList<String>>()
fun uploaded_docs_retrival() {
viewModelScope.launch(Dispatchers.IO){
livedata.postValue(repository.uploaded_docs_retrival())
}
}
I am trying to call the function from View Model and the error I am seeing is:
W/Firestore: (24.0.1) [WatchStream]: (297224f) Stream closed with status: Status{code=INTERNAL, description=error in frame handler, cause=java.lang.NoSuchMethodError: No interface method getBuffer()Lokio/Buffer; in class Lokio/BufferedSource; or its super classes (declaration of 'okio.BufferedSource' appears in /data/app/~~zy8Sr4ZK3BufSuP5iCevdQ==/com.example.alliaiseV1-OysKU8xYFaKtBxHIS_ndvw==/base.apk!classes15.dex)
at io.grpc.okhttp.OkHttpClientTransport$ClientFrameHandler.data(OkHttpClientTransport.java:1144)
at io.grpc.okhttp.internal.framed.Http2$Reader.readData(Http2.java:234)
at io.grpc.okhttp.internal.framed.Http2$Reader.nextFrame(Http2.java:147)
at io.grpc.okhttp.OkHttpClientTransport$ClientFrameHandler.run(OkHttpClientTransport.java:1103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
}.
W/Firestore: (24.0.1) [OnlineStateTracker]: Could not reach Cloud Firestore backend.
Connection failed 1 times. Most recent error: Status{code=INTERNAL, description=error
in frame handler, cause=java.lang.NoSuchMethodError: No interface method
getBuffer()Lokio/Buffer; in class Lokio/BufferedSource; or its super classes
(declaration of 'okio.BufferedSource' appears in
/data/app/~~zy8Sr4ZK3BufSuP5iCevdQ==/com.example.alliaiseV1-
OysKU8xYFaKtBxHIS_ndvw==/base.apk!classes15.dex)
at io.grpc.okhttp.OkHttpClientTransport$ClientFrameHandler.data(OkHttpClientTransport.java:1144)
at io.grpc.okhttp.internal.framed.Http2$Reader.readData(Http2.java:234)
at io.grpc.okhttp.internal.framed.Http2$Reader.nextFrame(Http2.java:147)
at io.grpc.okhttp.OkHttpClientTransport$ClientFrameHandler.run(OkHttpClientTransport.java:1103)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
}
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.
E/TAG: Failed to upload: Collection is empty.
The TAG in last line of error Indicates I am getting a Exception in My Repository Function Which is the First Function of this Question Mentioned Above.
However if I modify the Function to below and I don't use View Model and Directly Code the Function below in the Fragment and check the Logcat it is Retrieving perfectly
Altered Trying Code:
suspend fun uploaded_docs_retrival(): ArrayList<String> {
return try {
val result = Firebase.firestore.collection("profiles").whereEqualTo("UID", "YHMauLouORRtrYBV2h4dHJ5A0s72").get()
.await()
result.first().toObject(docretreving::class.java).Docs
} catch (e: Exception) {
Log.e("TAG", "Failed to upload: ${e.message.orEmpty()}")
ArrayList()
}
}
lifecycleScope.launch {
val z = uploaded_docs_retrival()
Log.d("Cross","$z")
}
How can the same Code work and if I use View Models and Live Data It crashes.
Help would be Appreciated , Been a quite While I am stuck with this.
Thanks in Advance
Looks like a library is missing. Try adding:
implementation("com.squareup.okhttp3:okhttp:4.9.3")

Coroutines with Retrofit crashing with no stack trace when calling `RequestBody.create`

I am using Retrofit with coroutines (built in support). I have a Retrofit interface, retrofit implementation and the API implementation created by Retrofit, but it doesn't matter as it doesn't get called. It crashes before that, here:
In XService.kt
suspend fun test() {
val mediaType = MediaType.parse("text/plain")
val requestBody = RequestBody.create(mediaType, "TEST STRING") // Crashes here
// Now make some network requests
}
which is called by a viewModel:
suspend fun test() {
return withContext(viewModelScope.coroutineContext) {
service.test()
}
}
which is called by a Fragment:
lifecycleScope.launch() { model.test() }
Unhelpful error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: package_name, PID: 9729
I/Process: Sending signal. PID: 9729 SIG: 9
I'm just not sure why creating a RequestBody causes a crash. What is weird is, when debugging and going slowly through the code, it doesn't crash... I have simplified the code so its easier for you to read, but the reason why its scoped to Fragment, not VM is because I want the Fragment to change the UI based on the response.
EDIT: It turns out if I wrap it in a try/ catch block, the line which crashes usually doesn't crash. Instead, the network call afterwards does, giving printing out:
I/System.out: java.net.UnknownHostException: Unable to resolve host "qats.orth.uk": No address associated with hostname
try {
val requestBody = RequestBody.create(mediaType, mode.toString())
return api.createQuiz(requestBody).createResult()
} catch (e: Exception) {
println(e)
}
So I am confused. Why does putting it in a try/catch block change what error message I get. Without try/catch, I got a useless crash with no stacktrace. I guess this may be the challenge with coroutines.

PublishSubject onError function in Kotlin

So, I am getting an error in my Android app (Kotlin) when trying to subscribe to a PublishSubject.
The error explanation is pretty straight forward, however, I have failed trying to implement this, onError function and I am not sure how to do it in a god way.
Here the error
The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | com.androidnetworking.error.ANError
Here the PublishSubject:
var positionSubject = PublishSubject.create<Location>()
Here when I subscribe (which gives error inside the code of the subscription):
compositeDisposable.add(
positionSubject.subscribe {
// do some actions here that causes Exception
}
)
Here my attempt to fix it in a "nice" way (did not work, still crashes in subscribe):
compositeDisposable.add(
positionSubject
.onErrorReturn { t ->
Log.d("debug", "EXCEPTION OCCURRED")
Location("")}
.subscribe {
// do some actions here that causes Exception
}
)
Here what I ended up doing to fix it and not crashing:
compositeDisposable.add(
positionSubject.subscribe {
try{
// do some actions here that causes Exception
}catch(e:Exception){
Log.d("debug", "EXCEPTION OCCURRED $e")
}
}
)
I am wondering how to this in a cleaner way than using the try/catch block inside the subscribe, if it is even possible.
Following code is kotlin way to subscribe a PublishSubject
var positionSubject = PublishSubject.create<Location>()
positionSubject.subscribe({ location ->
}, { error ->
})
This should work fine.

Unable to Handle Retrofit Connection Error in Kotlin Coroutine

I was trying to make an API request inside a Kotlin Coroutines. I have wrapped all code inside the coroutine with a try-catch block.
viewModelScope.launch {
try {
val temp = repository.searchMatch(query ?: "")
liveData.postValue(temp)
} catch (e: Exception) {
Log.d(TAG, e.message.toString())
}
}
The problem is, if I turning off the network while the request still running, the exception gets caught but also my app gets crashed because of the uncaught exception.
This is the uncaught exception I got:
android.system.ErrnoException: read failed: ENETDOWN (Network is down)
at libcore.io.Linux.readBytes(Native Method)
at libcore.io.Linux.read(Linux.java:184)
at libcore.io.BlockGuardOs.read(BlockGuardOs.java:254)
at android.system.Os.read(Os.java:414)
at android.net.util.PacketReader.readPacket(PacketReader.java:137)
at android.net.util.PacketReader.handleInput(PacketReader.java:207)
at android.net.util.PacketReader.access$100(PacketReader.java:70)
at android.net.util.PacketReader$1.onFileDescriptorEvents(PacketReader.java:189)
at android.os.MessageQueue.dispatchEvents(MessageQueue.java:285)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:326)
at android.os.Looper.loop(Looper.java:165)
at android.os.HandlerThread.run(HandlerThread.java:65)
2020-08-13 23:48:49.326 1205-5265/? E/MtkDhcpClient: Read error
android.system.ErrnoException: read failed: ENETDOWN (Network is down)
at libcore.io.Linux.readBytes(Native Method)
at libcore.io.Linux.read(Linux.java:184)
at libcore.io.BlockGuardOs.read(BlockGuardOs.java:254)
at android.system.Os.read(Os.java:414)
at com.mediatek.net.dhcp.MtkDhcpClient$ReceiveThread.run(MtkDhcpClient.java:434)
I have tried to set a CoroutineExceptionHandler and use a SupervisorJob but nothing works.
Please help me!

Categories

Resources