نگاهی عمیق‌تر به RxJava 2 – بخش دوم

آموزش اندروید آر ایکس اکس جاوا 2 rxjava 2 rxandroid rx reactive programming imperative programming برنامه نویسی ریاکتیو واکنشی android برنامه نویسی اندروید io.reactive ReactiveX , RxAndroid آموزش ویدیویی رایگان

سطح آموزش: #پیشرفته

منابع

علاوه بر منابعی که تو پست قبل گفتم برای این پست از این لینک هم استفاده زیادی کردم. اگر قبلا به RxJava 1 کار کرده باشید خوندن این لینک به تنهایی بهتون امکان کار کردن با RxJava 2 رو میده. در هر صورت یک نگاهی بهش بندازید

 ادامه…

آخرین بحثتی که تو پست قبلی داشتیم مقایسه Flowable و Observable بود.

Observableها رو به عنوان سورس‌هایی از داده شناختیم که میتونن به شکل‌های مختلف اطلاعات رو منتشر کنن. برای مثال دیدیم که کلیک روی یک button یا دریافت اطلاعات از اینترنت نوعی انتشار داده‌ست.

اما تفاوت‌های بنیادی‌ای بین این منابع داده‌ وجود داره. برای مثال کلیک روی button هیچوقت تموم نمیشه. نقطه‌ای نیست که بگیم خب دیگه خیلی روی این view کلیک کردی بسته. از طرفی وقتی یک observable مسئول دریافت یک داده‌ای از اینترنت میشه این کار فقط یکبار اتفاق میفته و بعد دیگه کار observable تموم شده. اگر بخوایم مجددا درخواستی بدیم از یک observable دیگه استفاده می‌کنیم.

در مواردی مثل نوشتن اطلاعات روی دیتابیس هم عمل انتشار داده‌ای نداریم. یک task هست که یا موفق میشه یا شکست میخوره.

برای تمام این موارد ورژن‌های مختلفی از Observable پیش‌بینی شده که کارمون رو راحت‌تر میکنن.

توجه کنید که این‌ها همه ورژن‌هایی از Observable هستن و نه Flowable و از backpressure پشتیبانی نمیکنن.

Single

single دو حالت داره. یا موفق میشه یا شکست میخوره.

در حالتی که موفق میشه onSuccess اجرا میشه و یک آیتم برمی‌گردونه و در صورتی که شکست بخوره onError اجرا میشه.

متدهایی که برای Observable داریم رو برای single هم داریم. مثال زیر یک single با just هست:

Completable

ایده‌اش ازینجا میاد که یکسری کارها عملا خروجی ندارن و فقط یا موفق میشن یا شکست میخورن. میشه گفت یکجور runnable هستن که reactive عمل می‌کنن. داخل runnable ما عملیات انجام میدیم و انتظار خروجی نداریم. مثلا نوشتن اطلاعات روی دیتابیس.

Maybe

Maybe یا موفق میشه و یک آیتم بر می‌گردونه، یا تموم میشه و هیچ آیتمی بر نمیگردونه یا اینکه به مشکل بر میخوره و error میده.

Maybe مخلوطی از single و completable هست. setterها توی جاوا رو در نظر بگیرید. یک setter همیشه completableـه به این دلیل که تنها کار setter اینه که یک مقداری رو به یک متغیر assign کنه و خروجی‌ای نخواهد داشت ولی مثال کار با دیتابیس ممکنه ما بخوایم روی دیتابیس چیزی بنویسیم که در اینصورت کارمون complete خواهد داشت و مقداری رو برنمیگردونه یا اینکه ممکنه بخوایم چیزی رو از روی دیتابیس بخونیم که در اینصورت maybe توی onSuccess یک آیتم برای ما برمیگردونه.

کاربردها

fromArray و fromIterable

هم Observable و هم Flowable مشابه کاری که با just میکنن میتونن یک آرایه یا اساسا هر نوع لیستی که قابلیت پیمایش داشته باشه رو emit کنن.

fromCallabe

fromCallable یک متد پرکاربرد هست که انواع کارها رو میشه باهاش کرد. به طور کلی fromCallabe یک رفتار سنکرون که یک مقدار واحد برمیگردونه رو بصورت آسنکرون مدل میکنه.

خوبی fromCallable اینه که میتونه exception تولید کنه. یعنی اگر موقع انجام اون رفتار سنکرونی که بهش دادیم مشکلی پیش بیام برنامه کرش نمیکنه و throw exception میکنه. سادگی استفاده از throw exception قابل مقایسه با try catch نیست. البته try-catch سخت نیست ولی هم به خطوط کد اضافه می‌کنه و هم پرانتزهای تو در تو تری برامون می‌سازه. و من از پرانتزای تو در تو متنفرم!

چندتا کاربردش رو الان بررسی می‌کنیم. از روی تعریفی که کردم میتونید حدس بزنید که وقتی بخوایم یه متد رو اجرا کنیم و مقدار برگشتی متد هم برامون مهم باشه fromCallabe میتونه کمکمون کنه.

مثلا بخوایم با سرور ارتباط برقرار کنیم کدی شبیه به زیر می‌نویسیم:

یا مثال زیر (منبع مثال) که Preferences رو پاک می‌کنه:

عملیات sharedPreferences.edit().clear().commit() a در حالت عادی سنکرون هست ولی ما با fromCallable و با استفاده از یک Observable این عملیات رو انجام میدیم و به هر Observerـی میتونیم بهش متصل شیم.

البته این کارها رو بدون callable هم میشه با observable انجام داد ولی بهترین روش به نظر من callable هست.

مثلا همین مورد آخر رو با create هم میشه به شکل زیر انجام داد (create موضوع بعدی بحثمونه):

کد

یک حرف بی‌ربط: شاید متوجه شده باشید من بعضی جاها از -> استفاده می‌کنم و خیلی از کدها رو نمی‌نویسم. در آینده راجع به این شکل کد زدن بیشتر حرف میزنیم ولی در حال حاضر میتونید با جستجو lambda راجع بهش اطلاعاتی کسب کنید. اگر هم میدونید چیه با استفاده از کتابخونه retrolambda میتونید داخل اندروید ازش استفاده کنید.

fromCallable برای Completable؟

احتمالا این سوال براتون پیش اومده که completable که فقط یه Task رو انجام میده و تموم میشه آیا fromCallable داره؟

جواب اینه که هم completable و هم maybe هر دو fromCallable رو دارن فقط اتفاقی که میفته اینه که مقداری که fromCallable برمیگردونه رو ignore میکنن. البته maybe لزوما ignore نمیکنه، فقط در مواردی که onComplete اجرا میشه و نه onSuccess.

همچنین دو تا متد fromAction و fromRunnable هم برای Maybe و Completable وجود داره که مقداری رو برنمیگردونه و فقط یک task رو انجام میده.

create

شاید پرکاربردترین متد برای تولید observableها همین create باشه. توی مثال بالا هم دیدیم که حتی کار fromCallable رو هم میشه با create انجام داد.

اساس کار create اینه که یک امیتر(emitter) به ما میده که با استفاده از اون هرجا بخوایم میتونیم دیتا emit کنیم. هر بار که emit انجام میدیم onNextـه observerها اجرا میشه. همچنین با emiterمون میتونیم onComplete رو صدا کنیم و کار تموم شه.

من کد کامل مثال بالا رو می‌نویسم:

خط اول ObservableOnSubscribe رو داریم. ObservableOnSubscribe یک callback هست که میگه هروقت یه subscriber جدید بود اجرا شو.

پس هروقت عمل subscribe انجام میشه کدهای داخل این callback هم اجرا میشه.

در ادامه هم ObservableEmitter رو داریم. قبلا گفتم emitter ها منتشر کننده داده هستن. به تعبیر وارتون امیتر کسیه که داره گوش میده. پس ما میتونید داده رو برای امیتر بفرستیم. در این تعبیر هم امیتر در واقع اون چیزی که بهش میدیم رو برای observer ها منتشر میکنه.

 

کار با سرور با استفاده از create

از اول که کار با RxJava رو شروع کردیم می‌گفتم خوبیِ RxJava اینه که میتونیم بگیم هروقت داده ما آماده شد این کار رو بکن. الان می‌بینیم که چطور این کار انجام میشه.

شاید این سوال پیش بیاد که خب در حالت عادی هم که وقتی دیتا آماده میشد داخل onResponse میگفتیم که مثلا فلان متد رو صدا کن و…

درسته این حرف اما الان فرقی که کرده اینه که ما هروقت داده آماده بشه با صدا کردن onNext اون رو emit میکنیم بنابراین هرکسی که در حال observe باشه از اومدن داده مطلع میشه و اجرا میشه.

همچنین الان وقتی unsubscribe صورت بگیره میتونیم منابع رو به راحتی آزاد کنیم. البته بازم این حرف درسته که بدون Rx هم میشد این کارو کرد ولی خب الان راحت‌تره.

منابع Observer

تا اینجا راجع به منابع ایجاد کننده صحبت کردیم. در نگاه کلان Flowable و Observable و بعد هم جایگزین‌های ساده‌ترِ observable یعنی single – completable – maybe رو شناختیم.

در ادامه منابع observe کننده رو می‌شناسیم. آخرین متدی که برای ساختار observable و flowable رو به یاد بیارید:

چطور میشه مقدار Disposable یا subscription رو به عنوان خروجی از observer یا subscriber گرفت؟

گفتیم که با disposable یا مترادفش subscription (اجازه بدید از این به بعد موارد رو فقط برای observable بگم چون هر دو تو این موارد یکی هستن و فقط اسامی تفاوت مختصری داره) میشه unsubscribe کرد. اما مادامی که این متد داخل observer هست یکمی عجیبه که ازش خروجی بگیریم.

در واقعیت ما از این متدها به این شکل استفاده نمی‌کنیم و به جاش از DisposableObserver استفاده می‌کنیم که متد چهارم رو نداره و به جاش مقدار اون رو خروجی میده. به کد زیر نگاه کنید:

حالا برای dispose کردن و آزاد کردن منابع کافیه observer رو در قالب شیء نگهدارید و هروقت خواستید dispose کنید:

یک روش دیگه هم برای این کار وجود داره. یک متدی داریم تحت عنوان subscribeWith که به عنوان خروجی یک disposable به ما میده. استفاده ازش خیلی شبیه به مثال بالاست فقط کمکمون میکنه چند خطی صرفه‌جویی کنیم.

همچنین قبلا با مفهوم CompositeDisposable آشنا شدیم. با استفاده از CompositeDisposable میتونیم چندین disposable رو همزمان dispose کنیم.

کی از کودوم استفاده کنیم؟

شیوه‌ای که من استفاده میکنم اینه که همیشه از subscribeWith استفاده می‌کنم. برای dispose کردن هم اگر فکر کنم ممکنه جایی لازم شه این observer رو به تنهایی dispose کنم، از یک disposable جدا استفاده می‌کنم اما در غیر اینصورت از CompositeDisposable استفاده می‌کنم.

استفاده از CompositeDisposable باعث میشه فراموش نکنم با destroy شدن اکتیویتی، observerها رو dispose کنم.

Operators

قبلا با بررسی چند مثال اپراتورها رو بررسی کردیم اما دوباره “نگاهی عمیق‌تر”طور میخوایم راجع بهشون صحبت کنیم. ولی لازمه قبلش یک نگاهی به مثال‌ها کرده باشید.

باز هم از خودِ مثال‌های وارتون استفاده می‌کنم:

اینجا ما الان یه عملیات (operation) رو به یک String اعمال می‌کنیم و یک String دیگه میگیریم. توی دنیایِ reactive این کار رو به شکل زیر انجام میدیم:

همچنین ما میتونیم تعیین کنیم هر کودوم از این عملیات‌ها روی چه threadـی انجام بشه. وقتی کارهایی مربوط به UI داریم در thread اصلی کار رو انجام میدیم و در غیر اینصورت عملیات‌ها رو در ترد های دیگه انجام میدیم.

یکی از قدرت‌های RxJava همین multithreading سادشه. در حالت عادی خیلی پیچیده میشه اگر ما بخوایم عملیات‌های مخلتف رو در thread های گوناگون انجام بدیم ولی توی RxJava خیلی راحت می‌تونیم عملیات‌ها رو در تردهای مختلف انجام بدیم بدون اینکه خودمون رو درگیر پیچیدگی‌ها کنیم.

یکی دیگه از خوبی‌های RxJava هم اینه که Operatorها مجددا observable برمیگردونن برای همین ما میتونیم عملیات‌هامون رو به دنیال هم انجام بدیم.

الان گفتیم عملیات subscribe روی یک thread انجام بشه. عملیات observe روی ترد اصلی یا ui انجام شه.

توجه کنید که ترتیب این عملیات‌ها مهمه. یعنی الان عملیات map روی ترد اصلی انجام میشه. در صورتی که نمیخوایم این عملیات داخل ترد اصلی انجام بشه باید جاش رو با خط بالاییش عوض کنیم.

 

پایان

سعی کردم بحث RxJava رو تا حدی تکمیل کنم که بتونید به طور عملی توی پروژه‌هاتون ازش استفاده کنید. RxJava بیشتر از اینکه با خوندن و ویدیو آموزشی بشه یادش گرفت نیاز به تمرین داره.

البته کار ما با RxJava کامل تموم نشده و در آینده از خودِ RxJava و دیگر کتابخونه‌های reactive به طور عملی توی پروژه‌ها استفاده خواهم کرد. اما فکر می‌کنم در حال حاضر هم برای اینکه بتونید توی پروژه‌هاتون از RxJava استفاده کنید به اندازه کافی معلومات دارید.

پی‌نوشت: javadoc

12 دیدگاه برای “نگاهی عمیق‌تر به RxJava 2 – بخش دوم

    1. سلام. وقتی بخوایم بیشتر از یک scope برای یک بخش داشته باشیم و همچنین برای encapsulate کردن دو بخش از همدیگه از subcomponent استفاده می‌کنیم. برای توضیحات بیشتر و دیدن مثال‌هاش داکیومنت‌های کتابخونه رو نگاه کنید. همچنین اگه لازم باشه با subcomponent کردن LifeCycle متغیرها رو یکی می‌کنیم.

  1. سلام میشه یک observer رو جنرال تو سطح تمام اپلیکیشن استفاده کرد؟
    من اکتیوی های A , B , C ,D دارم و زمانی که در اکتیویتی های B,C,D یک کارهایی صورت میگیره ،یک سری ویو هارو در اکتیویتی A اپدیت میکنم(اطلاعات رو از سرور دوباره میگیرم و اپدیت میکنم) ، برای این کار از بروکست ریسیور ها استفاده کردم میتونم از RX استفاده کنم و یک Observer رو پابلیک استاتیک تو اکتیویتی A تعریف کنم و در اکتیویتی های دیگه ازون استفاده کنم ؟

  2. ممنون ازش استفاده کردم من یه اپی نوشتم خیلی بزرگه و الان میخوام که اون dagger و یا این rx رو روش اعمال کنم ولی نمیدونم کجا شما میتونید راهنمایی کنید؟

  3. سلام
    من تا به حال فکر میکردم که با توجه به بازخوردها خیلی خوب برنامه نویسی میکنم ولی الان با آشنایی با RX فهمیدم که اصلا نمیتونم به خودم بگم برنامه نویس، و فقط کسی بودم الکی و درهم کد کنار هم میزاشتم.
    مقلاتی که در مورد RxJava گذاشتید بسیار عالی و قابل درک بود. ( من قبلش کلی منابع خارجی خونده بودم ولی مطالب شما اونا رو کاملا قابل درک کرد ).
    تشکر فراوان دارم ازتون که این مطالب رو به صورت رایگان و با صرف وقت بسیار در اختیار ما گذاشتید.
    از ته دل براتون آرزوی موفقت بسیار دارم. ۳>

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *