subscribe function is not working - kotlin

I am trying the basics of RxJava2.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_vogella)
setSupportActionBar(toolbar)
val todoObserverable= createObservable();
try {
todoObserverable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe ({ t-> Log.e(TAG,t.title)}, {e-> Log.e(TAG,e.localizedMessage)})
}catch (e:Exception){
e.printStackTrace()
}
}
get observable function:
fun createObservable():Observable<Book>{
val bookObservable: Observable<Book> = Observable.create { object :ObservableOnSubscribe<Book>{
override fun subscribe(emitter: ObservableEmitter<Book>) {
Log.e(TAG,"anc")
try {
val bookArrayList:ArrayList<Book> = ArrayList()
val bookOne= Book("XYZ")
val bookTwo= Book("ANC")
val bookThree= Book("3ewrXYZ")
val bookFour= Book("XwerweYZ")
bookArrayList.add(bookOne)
bookArrayList.add(bookTwo)
bookArrayList.add(bookThree)
bookArrayList.add(bookFour)
for (todo in bookArrayList){
emitter.onNext(todo)
Log.e(TAG,"on next")
}
emitter.onComplete()
}catch (e:Exception){
e.printStackTrace()
}
}
}
}
return bookObservable;
}
But I am unable to print the title of the book. It is not giving me any kind of error or exception.
I tried to debug the createObservable() but curser is not going inside the subscribe function.
Any hint will be helpful.

Observable.create { object :ObservableOnSubscribe<Book>{ - This essentially creates a ObservableOnSubscribe within a ObservableOnSubscribe. The object declaration is redundant or you can remove the lambda definition. (Observable.create(object : ETC))

Related

Is it possible to stop the flow 's collection from collect's code block?

I am a newbie in coroutine/flow and would like to know the appropriate way to close the flow from the collect's code block when it gets the value it wanted.
The code like this:
suspend fun findService(scope:CoroutineScope, context:Context, name:String) {
val flow = getWifiDebuggingConnectDiscoveryFlow( context )
try {
flow.collect {
if(name == it.serviceName) {
/* need to exit the collection and execute the code that follows */
}
}
println("service found!")
} catch(e: Throwable) {
println("Exception from the flow: $e")
}
/* need to do something after service found */
}
private fun getWifiDebuggingConnectDiscoveryFlow(context:Context) = callbackFlow {
val nsdManager:NsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager
val listener = object : NsdManager.DiscoveryListener {
override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) {cancel("onStartDiscoveryFailed")}
override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) {cancel("onStopDiscoveryFailed")}
override fun onDiscoveryStarted(serviceType: String?) {}
override fun onDiscoveryStopped(serviceType: String?) {}
override fun onServiceLost(serviceInfo: NsdServiceInfo?) {}
override fun onServiceFound(serviceInfo: NsdServiceInfo?) {
if(serviceInfo==null) return
trySend(serviceInfo)
}
}
nsdManager.discoverServices(ServiceDiscovery.ADB_CONNECT_TYPE, NsdManager.PROTOCOL_DNS_SD, listener)
awaitClose { nsdManager.stopServiceDiscovery(listener) }
}
This problem has been bothering me for a long time, and I would appreciate any help I get.
You can use the first or firstOrNull operators. It will stop collecting as soon as the first element that complies the condition is received:
val service = flow.firstOrNull { name == it.serviceName }
...
You can find first official documentation here

How to use Coroutines with Retrofit2?

I am fetching data from an api to display in a RecycerView using Retrofit2 and Kotlin Coroutines. I have just started learning Retrofit and Coroutines and at the moment the data is not displaying and I'm not sure how to solve it! I think the issue may be with the Coroutines code. Please can someone give me some help?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var recyclerView: RecyclerView = findViewById(R.id.rockets_list)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = RecyclerAdapter(List<RocketData>())
CoroutineScope(IO).launch {
val response = ApiInterface.getApi().getRockets()
Log.i("code",response.toString())
withContext(Dispatchers.Main) {
try {
if (response.isSuccessful) {
recyclerView.adapter
} else {
Toast.makeText(this#MainActivity, "Error ${response.code()}", Toast.LENGTH_SHORT).show()
}
} catch (e: HttpException) {
Toast.makeText(this#MainActivity, "Exception ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
}
interface ApiInterface {
#GET("rockets")
suspend fun getRockets(): Response<List<RocketData>>
companion object {
fun getApi(): ApiInterface = Retrofit.Builder()
.baseUrl("https://api.spacexdata.com/v3/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiInterface::class.java)
}
}
What are you doing after response.isSuccessful check??
try setting response in Adapter then notifyDataSetChanged
recyclerView.adapter.items = response
recyclerView.adapter.notifyDataSetChanged()
your Retrofit and Coroutine implementation works fine,
you just didn't update your adapter list after successful response check
if (response.isSuccessful) {
recyclerView.adapter.list = response.body
recyclerView.adapter.notifyDataSetChanged()
}
also you can't display Toast from within a Coroutine, wrap it inside runOnUiThread{}

subscribing to an observable in the chain and setting the observer to the observable

kotlin 1.2.60
rxJava 2
I have the following code snippet below. I am wondering what is the difference in using the subscribe that is chained to the end of flatmap and printing the results or creating an observer and subscribing to the Observable.
For some reason I was expecting to get the same results. But when I print out the result in the onNext it displays the complete emitted item.
However, for the chained on subscribe it displays what I would expect.
fun main(args: Array<String>) {
val source2 = Observable.just("521934/2342/FOXTROT", "21962/12112/78886/TANGO", "283242/4542/WHISKEY/2348562")
source2.flatMap {
Observable.fromArray(*it.split("/").toTypedArray())
}
.subscribe { println(it) }
val observer = object : Observer<String> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: String) {
println(t)
}
override fun onError(e: Throwable) {
}
}
source2.subscribe(observer)
}
The output is below:
from the chained subscribe:
521934
2342
FOXTROT
21962
12112
78886
TANGO
283242
4542
WHISKEY
2348562
from onNext:
521934/2342/FOXTROT
21962/12112/78886/TANGO
283242/4542/WHISKEY/2348562
source2 is an immutable collection. You are observing it twice. You should capture the result of the flatmap in a new variable and then observe that.
fun main(args: Array<String>) {
val source2 = Observable.just("521934/2342/FOXTROT", "21962/12112/78886/TANGO", "283242/4542/WHISKEY/2348562")
val source3 = source2.flatMap {
Observable.fromArray(*it.split("/").toTypedArray())
}
source3.subscribe { println(it) }
val observer = object : Observer<String> {
override fun onComplete() {
}
override fun onSubscribe(d: Disposable) {
}
override fun onNext(t: String) {
println(t)
}
override fun onError(e: Throwable) {
}
}
source3.subscribe(observer)
}

kotlin, got “Type mismatch. Required: Disposable? Found: Unit” when using observer object instance in the subscribe()

Edit:
based on Dmitry Ikryanov's suggestion,
using DisposableObserver will compile, but it causes crash
io.reactivex.exceptions.ProtocolViolationException: It is not allowed to
subscribe with a(n) com.DataManager$theObserver$1 multiple times. Please
create a fresh instance of com.DataManager$theObserver$1 and subscribe that
to the target source instead.
the only code of subecribWith(), which has been called only once
fun initSession() {
if (mDisposable != null && mDisposable!!.isDisposed) {
mDisposable!!.dispose()
}
mDisposable = RxBus.listen(DataEvent::class.java).subscribeWith(theObserver) <=== crash at here
}
the DisposableObserver is a member variable of the class:
var theObserver: DisposableObserver<DataEvent> = object : DisposableObserver<DataEvent>() {
override fun onComplete() {
Log.e(TAG, "onComplete: All Done!") }
override fun onNext(t: DataEvent) {
Log.e(TAG, "Next: " + t)
onDataReady(t) }
override fun onError(e: Throwable) {
Log.e(TAG, "onError: ")
}
}
===
Original question:
trying to use RxJava subscribe() in kotlin, get an error “Type mismatch. Required: Disposable? Found: Unit”, not sure what it means, anyone knows?
class DataEvent {}
using RxBus
object RxBus {
private val publisher = PublishSubject.create<Any>()
fun publish(event: Any) {
publisher.onNext(event)
}
// Listen should return an Observable and not the publisher
// Using ofType we filter only events that match that class type
fun <T> listen(eventType: Class<T>): Observable<T> = publisher.ofType(eventType)
}
when call like this, it is ok:
mDisposable = RxBus.listen(DataEvent::class.java).subscribe({
onDataReady(it)
})
but when call the RxBus.listen(DataEvent::class.java).subscribe(observer) with defined observer instance
it shows red underline: “Type mismatch. Required: Disposable? Found: Unit”
mDisposable = RxBus.listen(DataEvent::class.java).subscribe(observer)
the observer is:
var observer: Observer<DataEvent> = object : Observer<DataEvent> {
override fun onSubscribe(d: Disposable) {
Log.e(TAG, "onSubscribe: ")
}
override fun onNext(#NonNull t: DataEvent) {
Log.e(TAG, "onNext: " + t)
onDataReady(t)
}
override fun onError(e: Throwable) {
Log.e(TAG, "onError: ")
}
override fun onComplete() {
Log.e(TAG, "onComplete: All Done!")
}
}
It's because in RxJava 2.0 method subscribe(observer) was changed and return nothing.
Unlike the Observable of version 1.x, subscribe(Observer) does not allow external cancellation of a subscription and the Observer instance is expected to expose such capability.
You can use subscribeWith(observer).
Example:
val disposable = Observable.just("Hello world!")
.delay(1, TimeUnit.SECONDS)
.subscribeWith(object : DisposableObserver<String>() {
public override fun onStart() {
println("Start!")
}
fun onNext(t: Int?) {
println(t)
}
override fun onError(t: Throwable) {
t.printStackTrace()
}
override fun onComplete() {
println("Done!")
}
})

kotlin getting a subscriber to observe an observable using RxJava2

Android Studio 3.0 Beta2
I have created 2 methods one that creates the observable and another that creates the subscriber.
However, I am having a issue try to get the subscriber to subscribe to the observable. In Java this would work, and I am trying to get it to work in Kotlin.
In my onCreate(..) method I am trying to set this. Is this the correct way to do this?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/* CANNOT SET SUBSCRIBER TO SUBCRIBE TO THE OBSERVABLE */
createStringObservable().subscribe(createStringSubscriber())
}
fun createStringObservable(): Observable<String> {
val myObservable: Observable<String> = Observable.create {
subscriber ->
subscriber.onNext("Hello, World!")
subscriber.onComplete()
}
return myObservable
}
fun createStringSubscriber(): Subscriber<String> {
val mySubscriber = object: Subscriber<String> {
override fun onNext(s: String) {
println(s)
}
override fun onComplete() {
println("onComplete")
}
override fun onError(e: Throwable) {
println("onError")
}
override fun onSubscribe(s: Subscription?) {
println("onSubscribe")
}
}
return mySubscriber
}
}
Many thanks for any suggestions,
pay close attention to the types.
Observable.subscribe() has three basic variants:
one that accepts no arguments
several that accept an io.reactivex.functions.Consumer
one that accepts an io.reactivex.Observer
the type you're attempting to subscribe with in your example is org.reactivestreams.Subscriber (defined as part of the Reactive Streams Specification). you can refer to the docs to get a fuller accounting of this type, but suffice to say it's not compatible with any of the overloaded Observable.subscribe() methods.
here's a modified example of your createStringSubscriber() method that will allow your code to compile:
fun createStringSubscriber(): Observer<String> {
val mySubscriber = object: Observer<String> {
override fun onNext(s: String) {
println(s)
}
override fun onComplete() {
println("onComplete")
}
override fun onError(e: Throwable) {
println("onError")
}
override fun onSubscribe(s: Disposable) {
println("onSubscribe")
}
}
return mySubscriber
}
the things changed are:
this returns an Observer type (instead of Subscriber)
onSubscribe() is passed a Disposable (instead of Subscription)
.. and as mentioned by 'Vincent Mimoun-Prat', lambda syntax can really shorten your code.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Here's an example using pure RxJava 2 (ie not using RxKotlin)
Observable.create<String> { emitter ->
emitter.onNext("Hello, World!")
emitter.onComplete()
}
.subscribe(
{ s -> println(s) },
{ e -> println(e) },
{ println("onComplete") }
)
// ...and here's an example using RxKotlin. The named arguments help
// to give your code a little more clarity
Observable.create<String> { emitter ->
emitter.onNext("Hello, World!")
emitter.onComplete()
}
.subscribeBy(
onNext = { s -> println(s) },
onError = { e -> println(e) },
onComplete = { println("onComplete") }
)
}
i hope that helps!
Have a look at RxKotlin, that will simplify a lot of things and make code more concise.
val list = listOf("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
list.toObservable() // extension function for Iterables
.filter { it.length >= 5 }
.subscribeBy( // named arguments for lambda Subscribers
onNext = { println(it) },
onError = { it.printStackTrace() },
onComplete = { println("Done!") }
)
val observer = object: Observer<Int> {
override fun onNext(t: Int) {
// Perform the value of `t`
}
override fun onComplete() {
// Perform something on complete
}
override fun onSubscribe(d: Disposable) {
// Disposable provided
}
override fun onError(e: Throwable) {
// Handling error
}
}