خانه » لایبرری های مفید و تجربیات شخصی خیلی مفید !!! » آموزش استفاده از RxJava در اندروید (RxAndroid)

آموزش استفاده از RxJava در اندروید (RxAndroid)

توسعه یک اپلیکیشن پیچیده که دارای ارتباطات زیاد network ، تعاملات باکاربر و انیمیشن های فراوانی هستند ، گاه بسیار پیچیده می شود. ReactiveX روش هایی را برای پیاده سازی وظایف سنکرون (غیر همزمان) و رخ داد ها ارائه می دهد.

در این آموزش از RxJava پیاده سازی از ReativeX برای جاوا می باشد که توسط NetFlix توسعه یافته است و بین برنامه نویسان Java طرفدار زیادی دارد. در این آموزش از RxAndroid برای استفاده در پروژه های اندرویدی استفاده می شود.

 

برای افزودن این لایبرری کد زیر را در بخش dependencies وارد کنید :

compile 'io.reactivex:rxandroid:1.1.0'

(نسخه ۱٫۱٫۰ زمان نوشتن این مطلب آخرین نسخه می باشد ، حتما قبل از استفاده آخرین نسخه را طریق گیت هاب پروژه دریافت کنید: https://github.com/ReactiveX/RxAndroid)

 

Observers و Observables

زمانی که از ReativeX استفاده می کنیم ، همیشه با ۲ مفهوم Observers (مشاهده کننده ها) و Observables (مشاهدات) سر و کار داریم.

درواقع Observables ها اطلاعاتی را منتشر می کنند ، و اگر Observers وجود داشته باشد می تواند آن را بگیرد.

خیلی شبیه به onClickListener ها ، وقتی که setOnClickListener می کنیم درواقع یک Observer برای زمان کلیک شدن قرار می دهیم.

 

Observable ، متد های استاتیک متفاوتی دارد که اعمال مختلفی رو انجام میده ، مثلا ساده ترین مثال استفاده از متد just هست که یک آبجکت رو به Observable می فرسته :

Observable.just("Hello"); // Emits "Hello"

خوب با کد بالا ، Observable آماده هست تا یک مشاهده گر subscribe شده و به محض subscribe شدن ، مقدار Hello را به آن بفرستد:

Observer<String> myObserver = new Observer<String>() {
    @Override
    public void onCompleted() {
        // Called when the observable has no more data to emit
    }
 
    @Override
    public void onError(Throwable e) {
        // Called when the observable encounters an error
    }
 
    @Override
    public void onNext(String s) {
        // Called each time the observable emits data
        Log.d("MY OBSERVER", s);
    }
};

این یک مشاهده گر (Observer) هست که قرار است برای Observable ما subscribe کند:

Observable.just("Hello").subscribe(myObserver);

یا اینکه می تونیم یک instance از Observable نگه داشته و به هر تعداد نیاز observer به آن subscribe کنیم :

Observable<String> myObservable = Observable.just("Hello"); // Emits "Hello"

// 
myObservable.subscribe(myObserver);

//
myObservable.subscribe(new Observer<String>() {
    @Override
    public void onCompleted() {
        // Called when the observable has no more data to emit
    }
 
    @Override
    public void onError(Throwable e) {
        // Called when the observable encounters an error
    }
 
    @Override
    public void onNext(String s) {
        // Called each time the observable emits data
        Log.d("MY OBSERVER", s);
    }
});

بعد از اجرای کد بالا به سرعت متد onNext با مقدار Hello فراخوانی می شود.

 

نوع Observer که در بالا استفاده شد ، یک نوع کامل می باشد که ۳ متد اینترفیس Observer را پیاده سازی کرده است ( کاربرد هر متد را در ادامه خوایم دید) ، اما اگر نیاز به یک مشاهده گر ساده تر دارید می توانید از Action1 هم استفاده کنید :

Action1<String> myAction = new Action1<String>() {
    @Override
    public void call(String s) {
        Log.d("My Action", s);
    }
};

این هم دقیقا مانند Observer کار می کند :

Observable.just("Hello").subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.d("My Action", s);
    }
});

مثال بالا ساده ترین نوع استفاده از ReactiveX بود ، حالا می خوایم از Operators ها استفاده کنیم و کمی از توانایی های این لایبرری استفاده کنیم:

from

میتونه کاربردی شبیه به foreach داشته باشه

Observable<Integer> myArrayObservable 
    = Observable.from(new Integer[]{1, 2, 3, 4, 5, 6}); // Emits each item of the array, one at a time
 
myArrayObservable.subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer i) {
        Log.d("My Action", String.valueOf(i)); // Prints the number received
    }
});

این متد یک لیست یا آرایه را گرفته سپس به ازای هر آیتم ، observer را فراخوانی کرده و آن مقدار را می فرستد ( در مثال بالا ، ابتدا متد call با مقدار ۱ فراخوانی شده ، سپس با مثقدار ۲ و همین طور تا مقدار ۶)

خروجی قطعه کد بالا : 

My Action: 1
My Action: 2
My Action: 3
My Action: 4
My Action: 5
My Action: 6

۲ متد دیگر ، map و filter که در زبان هایی مثل Javascript ، Ruby یا Kotlin برای کار با آرایه ها وجود دارد ، و در اندروید (به دلیل استفاده از جاوا ۷ ) و نبودن lambdas ها وجود ندارد ، اما می توان توسط این لایبرری آن را شبیه سازی کرد :

map

استفاده از map :

myArrayObservable = myArrayObservable.map(new Func1<Integer, Integer>() { // Input and Output are both Integer
    @Override
    public Integer call(Integer integer) {
        return integer * integer; // Square the number
    }
});

یک observable به یک observable دیگر map می شود ، در واقع اتفاقی که می افتد ، فرض کنید لیستی شامل اعداد ۱ ، ۲ و ۳ داریم ، 

که توسط کد زیر به یک observable تبدیل شده است :

Observable<Integer> myArrayObservable
                = Observable.from(new Integer[]{1, 2, 3});

زمانی که map را روی آن اجرا می کنیم ، یک آرایه دیگر ، به همان اندازه درست شده و تک تک به ازای هر عدد متد call یک بار فراخوانی می شود سپس مقدار return در آرایه جدید قرار می گیرد:

First Array = {1,2,3}

Second Array= {,,}



call (1) - &gt;&gt; return 1*1&nbsp;

First Array = {1,2,3}

Second Array= {1,,}





call (2) - &gt;&gt; return 2*2&nbsp;

First Array = {1,2,3}

Second Array= {1,4,}



call (3) - &gt;&gt; return 3*3&nbsp;

First Array = {1,2,3}

Second Array= {1,4,9}

در بالا روند اجرای کد نشان داده شد ، سپس خروجی نهایی را در یک Observable داریم که می توانیم با subscribe کردن ، مقادیر آن را تک تک بدست آوریم.

 

filter

یک گام فراتر بریم و از filter استفاده کنیم

این متد هم مانند بالا بر روی لیست تک به تک اجرا شده ، و لیست جدیدی را می سازد ، اما این بار لیست جدید ، تعدادی برابر با لیست اول ندارد ، و فقط مقادیری که true برگردانده اند در لیست جدید موجود می باشند :

myArrayObservable
    .filter(new Func1<Integer, Boolean>() {
        @Override
        public Boolean call(Integer integer) { // Ignores any item that returns false
            return integer % 2 == 0; 
        }
    });

به طور مثال کد بالا ، در صورتی true بر می گرداند که عدد موجود ، بر ۲ بخش پذیر باشد که در صورت اجرای آن روی آرایه ای که پیش از این داشتیم خواهیم داشت :

First Array = {1,2,3}

Second Array= {}



call (1) - >> return false (1%2=1)

First Array = {1,2,3}

Second Array= {}





call (2) - >> return true (2%2=0)

First Array = {1,2,3}

Second Array ={2}



call (3) - >> return false (3%2=1)

First Array = {1,2,3}

Second Array = {2}

و خروجی filter نیز یک observable هست ، به دلیل اینکه خروجی ها همه از نوع observable هستند ، می توان چند متد را پشت سر هم نیز اجرا کرد ، مثلا بعد از map کردن ، filter هم کرد و در نهایت subscribe کرده.

 

skip

متد دیگر متد skip هست که می تواند از به مقدار مشخص شده مقادیر را از قلم بیندازد:

myArrayObservable.skip(2); // Skip the first two items

 

وظایف غیر همزمان Asynchronous Jobs 

همان طور که پیشتر گفته شد یکی دیگر از توانایی های این لایبرری ، مدیریت Asynchronous Jobs ها می باشد ، به این صورت که می توان به جای AsynkTask نیز استفاده شود ، مزیتش نسبت به AsynkTask ساده تر بودن و همچنین مدیریت چندین کار به صورت موازی می باشد، در مثال زیر قصد خواندن دیتا از ۲ سایت را داریم ( مثلا با متد زیر)

String content = fetchData("http://www.google.com");
// fetches the contents of google.com as a String

برای این کار نیاز داریم تا یک observable جدید درست کنیم که عمل مورد نظر مارو انجام بده (مثلا میتونیم یک observable شبیه map یا filter بسازیم) این کار را با استفاده از متد create انجام می دهیم

create

به مثال توجه کنید :

Observable<String> fetchFromGoogle = Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        try {
            String data = fetchData("http://www.google.com");
            subscriber.onNext(data); // Emit the contents of the URL
            subscriber.onCompleted(); // Nothing more to emit
        }catch(Exception e){
            subscriber.onError(e); // In case there are network errors
        }
    }
});

در اینجا یک Observable جدید ساخته شده ، که می تواند در یک thread جداگانه اجرا شود ، در این قطعه کد متد های onNest ، onCompleted و onError را مشاهده می کنید ، که تا زمانی که متد onCompleted فراخوانی نشود observer منتظر متد onNext بعدی است و بسته نمی شود.

خوب حالا برای اینکه به این subscribe کنیم این دفعه کمی متفاوت تر عمل می کنیم :

fetchFromGoogle
    .subscribeOn(Schedulers.newThread()) // Create a new Thread
    .observeOn(AndroidSchedulers.mainThread()) // Use the UI thread
    .subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
            view.setText(view.getText() + "\n" + s); // Change a View
        }
    });

همان طور که می بینید ، قبل از subscribe کردن ، ۲ متد subscribeOn و observeOn فراخوانی و مقدار دهی شده اند ، که این مشخص می کند ، observable ما که در چند خط بالا ساختیم باید در یک newThread کار کند ولی observer مقادیر آن را در mainThread ( همان UI thread اندروید) دریافت کند.

خوب تا اینجا شاید به جز ساده تر شدن چند خط کد ، برتریت چندانی نسبت به AsynkTask نبینیم ، ولی زمانی که تعداد درخواست های موازی (همزمان) به سرور زیاد می شوند ، کارایی این لایبرری مشاهده می شود

فرض کنید به جای یک observer که اسمش fetchFromGoogle بود ، observer دیگری به اسم fetchFromYahoo داریم ، قصد داریم در زمان شروع کار اکتیویتی ، همزمان ۲ درخواست ارسال شوند و پاسخ زمانی که هر ۲ پاسخ دریافت شد نشان داده شود :

zip

در اینجا از متد zip استفاده می شود:

fetchFromGoogle = fetchFromGoogle.subscribeOn(Schedulers.newThread());
fetchFromYahoo = fetchFromYahoo.subscribeOn(Schedulers.newThread());

// Fetch from both simultaneously
Observable<String> zipped 
    = Observable.zip(fetchFromGoogle, fetchFromYahoo, new Func2<String, String, String>() {
        @Override
        public String call(String google, String yahoo) { 
            // Do something with the results of both threads
            return google + "\n" + yahoo;
        }
    });

متد zip هر ۲ درخواست را باهم اجرا کرده و پس از اینکه ۲ درخواست پاسخ را دریافت کنند ، پاسخ هارا به observer می فرستد.

 

خوب این مطلب تمام شد ، سعی کردم بخش های مهمی از آموزش سایت tutsplus رو در مورد RxJava قرار بدم که امیدوارم بدردتون بخوره.

موفق باشید

ایلیا عابدینی

منبع: http://code.tutsplus.com/tutorials/getting-started-with-reactivex-on-android–cms-24387

برچسب ها:
پست قبلی
پست بعدی

درباره ایلیا عابدینی

برنامه نویس اندروید و کارشناس مهندسی پزشکی، نفر سوم مسابقه برنامه نویسی اندروید http://www.schallenge.ir ، از سال 92 برنامه نویسی اندروید رو شروع کردم و در حال حاضر در شرکت عصر دانش در حال توسعه اپلیکیشن تجارت پی می باشدم ، این وبلاگ رو ساختم تا تجربیات روزانه و مفید خودم رو داخل اون بزارم. رزومه : iact.ir/cv

2 دیدگاه

  1. عالیه، مدت ها بود دنبال یه نقطه شروع برای کار با این مبحث بودم

  2. بسیار عالی بود موفق باشید

دیدگاهتان را ثبت کنید

آدرس ایمیل شما منتشر نمی شود.علامت دارها لازمند. *

*

رفتن به بالا