I started reading about RX on Android . I was trying to do a POST api call from within a rx chain. I wanted to see if this is the right way and that do I need to even create a disposable again when making the call and register the subscribe/observe threads again. Please see the comments in the code.
disposable.add(module.getInfo()
.flatMapSingleElement {
profile ->
profile.getDetails().map {
//IS THIS NEW DISPOSABLE NEEDED
newDisposable.add(
//Retrofit api to return Single<ResponseBody>
//IS THIS THE RIGHT WAY TO MAKE A SEQUENTIAL API CALL IN RX CONSUMING DATA FROM ANOTHER OPERATOR
module.saveImageDetails(
ImageDetails(imageId)
subscribeOn(Schedulers.io().observeOn(Schedulers.io())
.subscribe(
Consumer { handleResponse(it) },
createErrorHandler()
)
)
profile
}
}
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe(//do something)
Related
Before coroutines I used callbacks and debugging always gave me a lot of information. I could get the url my API call is going to, Headers I put into Request, interceptors I used, etc..
Now I use coroutines. All I can get when debugging is the final result of request (fail/sucess) with the result data. Nothing of all these valuable info I need is not there.
shortened example of my code:
restService.getVersionInfo().getResult(
success = {
when {
checkIsMandatory(it.lastMandatoryVersion) -> status.postValue(
Status.NewVersionInfo(it.description, true, it.url)
)
else -> initialization()
}
},
error = {
initialization()
}
I pout breakpoints to error or sucess. Am I missing something or coroutines really have this disadvantage. Please inform me
I have a Retrofit call where I want to handle HTTP and Retrofit errors when calling an API.
So when a failure happens, I need to cache the request into a RoomDB/SQLite for when the API comes back online, or connection improves there is a routine that sends all those requests to the API.
x.enqueue(object : Callback<PayloadResponse> {
override fun onResponse(
call: Call<PayloadResponse>,
response: Response<PayloadResponse>
) {
...
val errorMessage = when {
response.code() != HttpURLConnection.HTTP_OK -> {
// Need the original Payload here so I can insert that data into RoomDB/SQLite
"An error occured duing API Call (NOT OK) &{response.code()}"
}
...
Same situation I need for the onFailure() callback.
Can I access the original request in these contexts? If so how?
Once I have encountered the same problem. My approach was debugging first parameter of retrofit callback's onResponse and onFailure.
call: Call<PayloadResponse>
call.request()
It contains all kind of information about your call / request e.g url, parameters, method. However, retrieving request data is not straightforward, consistent, and prone to bugs.
Then, I started using Kotlin coroutine which gives async process with sync nature of coding.
interface RetrofitApi{
#GET("your-route")
suspend fun sampleApiMethod(request:SampleRequest):Response<SampleCustomObject>
}
Your retrofit api methods may look like above.
CoroutineScope(Dispatchers.Main).launch {
val request = SampleRequest()
val deferred = async { apiService.sampleApiMethod(request) }
val result = deferred.await()
if(result.code() == 200){
// Do something
}else{
// Cache SampleRequest()
}
}
You can modify as much as to make it look better and utilize optimized light weight threads. It is one of the ways for me to handle such situations. It's just a hint, you may modify to have structurally and architecturally correct design in your project.
I'm building an android application in which the user can choose a playlist from youtube and after choosing it I will need to load all the videos in that playlist into a single list.
I found several solutions online but they were using javascript and the ones that were written in rxjava the paginate was using int numbers rather then strings (I won't be able to use range).
For now I'm able to load the first 50 videos, I tried several approaches (one of which was a recursion but apparently I wrote it bad and I ended up using all the api requests in one load).
Here is my code:
fun getVidoesFromPlayList(playListId: String,pageToken: String): Single<MutableList<YTVideo>> {
return youTubeService.getPlayListResponse(playListId, pageToken)
.flatMap { response ->
Observable.just(response.items)
.flatMapIterable { data -> data }
.flatMap { item ->
youTubeService.getVideoResponse(item.snippet!!.resourceId!!.videoId).toObservable()
.subscribeOn(Schedulers.io())
.map { videoResponse ->
YTVideo(
item.snippet.position,
item.snippet.resourceId!!.videoId,
item.snippet.thumbnails!!.medium!!.url,
item.snippet.title,
videoResponse.items!![0].contentDetails!!.duration,
videoResponse.items[0].snippet!!.channelTitle
)
}
}
.repeatUntil { response.nextPageToken!=null }
.toList()
}
}
1) How can I call to getVidoesFromPlayList with a different nextpagetoken while caching the current videos?
2) Is there a way to do it more effecently without using recursion?
I will appreciate any help or guidance, thank you!
I work on Android (Kotlin) with a WebView who load some Page and i have interection with this page with
#JavascriptInterface
My client write some function i had to implement, for exemple :
#JavascriptInterface
fun fileExists(path: String): Promise<Boolean>? {
return null
}
But class Promise is not found, and I don't know what is it and which library I need to use.
His only answer is "Look how Cordova transforme Promise into Java Object"
Maybe someone can help me or just give some start of information, now I even don't know direction
I have try this 2
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
but not Pormise Object inside.
Thank you for your help
Promise as a pattern is well known in JS world, but it's not so popular among Android folks, maybe because of the fact that we have a very powerful RxJava library. But what if you need RxJava just for a single value response (Single) such as single network request and couple transformation operation like flatMap and map. If this is the case then you should consider Promise pattern that works well for single value response.
Example use of Promise:
fun postItem(item: Item) {
preparePostAsync()
.thenCompose { token ->
submitPostAsync(token, item)
}
.thenAccept { post ->
processPost(post)
}
}
fun preparePostAsync(): Promise<Token> {
// makes request an returns a promise that is completed later
return promise
}
I am making a network call using rxJava2, and based on the response (either success or error), I have to move my work forward on UI thread.
I have written the code below. It seems working fine.
WApi wApi = ServiceGenerator.createService(WApi.class, sURL);
dataManager = InventoryModule.getDataManager();
rx.Observable<GetFeature> getFeatureObservable =
dataManager.executeGetFeature(caseId, wrapperApi);
if (getCV2FeatureObservable != null) {
try {
getFeatureObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> {
Log.e(TAG, "Err::" + throwable.getMessage());
// init default values because of error response
initDefaultValues();
// No data to use from WS call. Move forward with
//cookie from SSO auth
cookieReceived(userID, cookieData, patchNo);
})
.onErrorResumeNext(rx.Observable.empty())
.subscribe(getFeature -> {
// use the data from WS response
processAndUpdateFeature(getFeature);
// move forward with cookie from SSO auth
cookieReceived(userID, cookieData, patchNo);
});
} catch (Exception e) {
Log.e(TAG, e.getLocalizedMessage());
}
}
Still I need opinions, Am I doing it right? Am I missing something? or can I use other operators and make it better? the way I am placing my UI work into corresponding operators, will it work properly in both error or success response?
The only questionable choice is all the complications you're doing on errors.
instead of using doOnError + onErrorResumeNext I suggest you move your logic to the Subscriber:
getFeatureObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getFeature -> {
// use the data from WS response
processAndUpdateFeature(getFeature);
// move forward with cookie from SSO auth
cookieReceived(userID, cookieData, patchNo);
}, { throwable -> {
Log.e(TAG, "Err::" + throwable.getMessage());
// init default values because of error response
initDefaultValues();
// No data to use from WS call. Move forward with
//cookie from SSO auth
cookieReceived(userID, cookieData, patchNo);
});
Your thread switching (subscribeOn and observeOn) is fine.
EDIT:
One more thing: Unless the processAndUpdateFeature or initDefaultValues or cookieReceived can throw an error, the try-catch block seems unnecessary.
In my experience I have had best luck using AsyncTask for network operations.
There are many advantages. 1) Use publish progress to show progress bar advancement. 2) You can have a single place to handle errors in a consistent way while also making the 'success' flow do different things. 3) AsyncTask is an Android construct so you have a good chance of it working consistently between versions.