پیش از شروع به خواندن توصیه میشود قسمت ۰ (مقدمه و آشنایی با ReactiveX) را مطالعه کنید.
قسمت ۰ - مقدمه
قسمت ۱ - Observable (در حال مطالعه هستید)
قسمت ۲ - انواع Observableها (انتشار 01-03-1399)
compile 'io.reactivex.rxjava2:rxkotlin:2.2.0'
در صورت نیاز، برای یافتن آخرین نسخه از Maven Repository استفاده کنید.
کلمه Observable به معنای آنچه که قابل مشاهده و بررسی میباشد معنا میدهد و در ReactiveX ما به عنوان Observer (مشاهدهگر) علاقهمند به اطلاعاتی که Observable در اختیار ما میگذارد هستیم. به رابطه بین Observer و Observable کلمه Subscription (عضویت) نسبت داده میشود:
برای تمرین تمام مثالها را داخل فانکشن main قرار دهید.
Observable.just("Bitcoin", "Ethereum", "Tether") .subscribeBy { currency -> println(currency) }
خروجی:
Bitcoin
Ethereum
Tether
در اینجا سه رمز ارز معروف بیتکوین، اتریوم و تتر را در داخل یک Observable داریم که توسط ما Subscribe (عضویت) صورت گرفته تا تمام آیتمهای آن چاپ شود.
این قسمت اطلاعات قابل مشاهده ما را تعریف میکند (Observable):
Observable.just("Bitcoin", "Ethereum", "Tether")
به فانکشنها در ReactiveX کلمه Operator اختصاص داده شده، مثلا just در اینجا یک Operator میباشد.
این قسمت ما خودمان را به عنوان مشاهدهگر (Observer) معرفی میکنیم:
.subscribeBy { currency -> println(currency) }
اپراتور just به معنای فقط در اینجا تنها (فقط) چندین اطلاعات را در خود نگهداری میکند. این اپراتور overload شده میباشد و بر اساس نیاز میتوانید تعداد دلخواه تا سقف مجاز نگهداری کنید.
امیدوارم بدانید Overload به معنای وجود چندین فانکشن با اسامی یکسان ولی امضاهای متفاوت میشود. امضا یا Signature همان ورودیهای آن فانکشن محسوب میشود، یعنی اگر در یک کلاس دو فانکشن نام یکسان add را داشتند یکی از آنها دو ورودی Int دریافت میکند، دیگری باید دو ورودی از نوع دیگر مثلا String یا تعداد متفاوت ورودی Int قبول کند.
هر Observable سه حالت کلی دارد:
در مثال قبلی subscribeBy تنها onNext را برای ما چاپ کرد ولی اینبار دو حالت دیگر را نیز اضافه میکنیم:
Observable.just("Bitcoin", "Ethereum", "Tether") .subscribeBy( onNext = { currency -> println(currency) }, onComplete = { println("Completed") }, = { println("Error") } )
خروجی:
Bitcoin
Ethereum
Tether
Completed
توجه داشته باشید که به علت عدم وجود خطا چاپ نمیشود.
هنگامی که دو فانکشن یا onComplete صدا زده میشوند عضویت (Subscription) بین Observer و Observable از بین میرود (Dispose میشود) در قسمتهای بعدی موقعیتهایی وجود دارد که حتما بایستی به صورت دستی این عضویتها را Dispose کنیم ولی در اینجا به علت اینکه Observable ما تنها چندین اطلاعات/رویداد در خود نگه میدارد و پس از اتمام یا onComplete به صورت خودکار صدا زده میشوند نیازی به این کار وجود ندارد.
نتیجه رابطه Observer و Observable یک Subscription میباشد:
val subscription = Observable.just("Bitcoin", "Ethereum", "Tether")
.subscribeBy {
println(it)
}
println("Is subscription disposed? -> ${subscription.isDisposed}")
استفاده از کالکشن در Observable:
روش اول تبدیل کالکشن به Observable که دارای سه آیتم است:
Observable<String>
listOf("Litecoin", "Monero", "TRON").toObservable() .subscribeBy { println(it) }
اپراتور toObservable یک کالکشن را تبدیل به Observable شامل سه آیتم میکند.
روش دوم تبدیل کل لیست به یک آیتم در Observable:
Observable<List<String>>
Observable.just(listOf("Litecoin", "Monero", "TRON")) .subscribeBy { currencyList: List<String> -> currencyList.forEach { println(it) } }
برای ساخت منطق شخصیسازی شده میتوانید از Operator ای به نام create استفاده کنید و با استفاده از Observable Emitter آن هر جا که نیاز داشتید رویداد onNext, , onComplete را صدا بزنید:
کلمه Emitter به معنای انتشار دهنده میباشد، در ReactiveX ما اطلاعات را به Observer انتشار میدهیم.
برای تست یکبار ورودی را سن واقعی خودتان و یکبار یک کاراکتر غیر عددی وارد کنید تا تفاوت را متوجه شوید.
val observable = Observable.create<String> { emitter -> println("Please enter your age:") val ageInput = readLine() ageInput ?: return@create try { val age = ageInput.toInt() if (age < 18) { emitter.onNext("User is under age: $age") } else { emitter.onNext("User is at appropriate age") } emitter.onComplete() } catch (exception: NumberFormatException) { emitter.(exception) } } val subscription = observable.subscribeBy( onNext = { message -> println(message) }, = { throwable -> println("Error, $throwable") }, onComplete = { println("Completed") } )
دلیل احتمال کرش کردن برنامه در کد بالا فانکشن toInt میباشد که توانایی تبدیل کاراکتر غیر عددی را به یک عدد ندارد و برنامه با Exception رو به رو خواهد شد و ما آن را Catch کرده و با RxKotlin یک رویداد خطا به مشاهدهگر انتشار میدهیم.
در قسمت بعدی با انواع Observableها و همچنین Side Effectها آشنا خواهیم شد. انواع زیر مجموعه Observable ها به ما کمک میکنند رویدادهای بهتر و مناسبتری به Observer ارائه دهیم.