Rxjava هو تنفيذ Java VM للامتدادات التفاعلية: مكتبة لتكوين البرامج غير المتزامنة والقائمة على الأحداث باستخدام تسلسلات يمكن ملاحظتها.
إنه يمتد نمط المراقب لدعم تسلسل البيانات/الأحداث ويضيف المشغلين الذين يسمحون لك بتكوين تسلسلات معًا بشكل معني مع استخلاص مخاوف بشأن أشياء مثل الخيوط ذات المستوى المنخفض ، المزامنة ، هياكل البيانات المتزامنة.
تعرف على المزيد حول Rxjava بشكل عام في منزل ويكي.
يرجى قراءة ما هو مختلف في 3.0 للحصول على تفاصيل حول التغييرات ومعلومات الترحيل عند الترقية من 2.x.
الإصدار 2.x هو نهاية العمر اعتبارًا من 28 فبراير 2021 . لن يحدث أي تطوير ودعم وصيانة و PRS والتحديثات. سيظل جافادوك من الإصدار الأخير ، 2.2.21 ، متاحًا.
الإصدار 1.x هو نهاية العمر اعتبارًا من 31 مارس 2018 . لن يحدث أي تطوير ودعم وصيانة و PRS والتحديثات. سيظل جافادوك من الإصدار الأخير ، 1.3.8 ، متاحًا.
الخطوة الأولى هي تضمين Rxjava 3 في مشروعك ، على سبيل المثال ، كاعتماد على ترجمة Gradle:
implementation " io.reactivex.rxjava3:rxjava:3.x.y "
(يرجى استبدال x
و y
بأحدث أرقام الإصدار :)
والثاني هو كتابة برنامج Hello World :
package rxjava . examples ;
import io . reactivex . rxjava3 . core .*;
public class HelloWorld {
public static void main ( String [] args ) {
Flowable . just ( "Hello world" ). subscribe ( System . out :: println );
}
}
لاحظ أن مكونات Rxjava 3 تعيش الآن تحت io.reactivex.rxjava3
والفئات والواجهات الأساسية تعيش تحت io.reactivex.rxjava3.core
.
يتميز Rxjava 3 بالعديد من الفصول الأساسية التي يمكنك اكتشافها على:
io.reactivex.rxjava3.core.Flowable
: 0..N التدفقات ، دعم الإرشادات التفاعلية وضغط الظهرio.reactivex.rxjava3.core.Observable
: 0..N التدفقات ، لا خلفية ،io.reactivex.rxjava3.core.Single
: تدفق عنصر واحد بالضبط أو خطأ ،io.reactivex.rxjava3.core.Completable
: تدفق بدون عناصر ولكن مجرد إكمال أو إشارة خطأ ،io.reactivex.rxjava3.core.Maybe
: تدفق بدون عناصر أو عنصر واحد أو خطأ.تتكون تدفقات البيانات في RXJava من مصدر أو صفر أو أكثر أو أكثر من خطوات متوسطة تليها مستهلك بيانات أو خطوة دمج (حيث تكون الخطوة مسؤولة عن استهلاك تدفق البيانات ببعض الوسائل):
source . operator1 (). operator2 (). operator3 (). subscribe ( consumer );
source . flatMap ( value -> source . operator1 (). operator2 (). operator3 ());
هنا ، إذا تخيلنا أنفسنا على operator2
، فإن النظر إلى اليسار نحو المصدر يسمى المنبع . النظر إلى اليمين نحو المشترك/المستهلك يسمى المصب . غالبًا ما يكون هذا أكثر وضوحًا عند كتابة كل عنصر على خط منفصل:
source
. operator1 ()
. operator2 ()
. operator3 ()
. subscribe ( consumer )
في وثائق RXJAVA ، تعتبر الانبعاثات ، والبند ، والعنصر ، والحدث ، والإشارة ، والبيانات والرسالة مرادفات وتمثل الكائن الذي يتجه على طول تدفق البيانات.
عندما يتم تشغيل Dataflow عبر خطوات غير متزامنة ، قد يؤدي كل خطوة أشياء مختلفة بسرعة مختلفة. لتجنب الساحق مثل هذه الخطوات ، والتي عادة ما تظهر نفسها على أنها زيادة استخدام الذاكرة بسبب التخزين المؤقت المؤقت أو الحاجة إلى تخطي/إسقاط البيانات ، يتم تطبيق ما يسمى بالضغط الخلفي ، وهو شكل من أشكال التحكم في التدفق حيث يمكن للخطوات التعبير عن عدد العناصر هل هم على استعداد للمعالجة. يسمح هذا بتقييد استخدام ذاكرة تدفقات البيانات في المواقف التي لا توجد فيها طريقة بشكل عام لخطوة لمعرفة عدد العناصر التي سيرسلها المنبع إليها.
في RXJAVA ، يتم تعيين فئة Flowable
المخصصة لدعم الضغط على الظهر ويمكن Observable
للعمليات غير المضغوطة (التسلسلات القصيرة ، تفاعلات واجهة المستخدم الرسومية ، إلخ). الأنواع الأخرى ، Single
، Maybe
Completable
لا تدعم الظهر ولا ينبغي لها ؛ هناك دائمًا مساحة لتخزين عنصر واحد مؤقتًا.
يحدث إعداد تدفقات البيانات من خلال تطبيق مختلف المشغلين الوسيطين في ما يسمى بوقت التجميع :
Flowable < Integer > flow = Flowable . range ( 1 , 5 )
. map ( v -> v * v )
. filter ( v -> v % 3 == 0 )
;
في هذه المرحلة ، لا تتدفق البيانات بعد ولا تحدث آثار جانبية.
هذه حالة مؤقتة عند استدعاء subscribe()
في تدفق يحدد سلسلة خطوات المعالجة داخليًا:
flow . subscribe ( System . out :: println )
هذا هو عندما يتم تشغيل الآثار الجانبية الاشتراك (انظر doOnSubscribe
). بعض المصادر تمنع أو تبدأ في انبعاث العناصر على الفور في هذه الحالة.
هذه هي الحالة عندما تنبعث التدفقات بنشاط عناصر أو أخطاء أو إشارات الانتهاء:
Observable . create ( emitter -> {
while (! emitter . isDisposed ()) {
long time = System . currentTimeMillis ();
emitter . onNext ( time );
if ( time % 2 != 0 ) {
emitter . onError ( new IllegalStateException ( "Odd millisecond!" ));
break ;
}
}
})
. subscribe ( System . out :: println , Throwable :: printStackTrace );
عمليا ، هذا هو عندما ينفذ جسم المثال المعطى أعلاه.
تتمثل إحدى حالات الاستخدام الشائعة لـ RXJAVA في تشغيل بعض الحسابات ، وطلب الشبكة على مؤشر ترابط الخلفية وإظهار النتائج (أو الخطأ) على مؤشر ترابط واجهة المستخدم:
import io . reactivex . rxjava3 . schedulers . Schedulers ;
Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
})
. subscribeOn ( Schedulers . io ())
. observeOn ( Schedulers . single ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 ); // <--- wait for the flow to finish
يسمى هذا النمط من طرق التسلسل واجهة برمجة تطبيقات بطلاقة تشبه نمط البناء . ومع ذلك ، فإن أنواع Rxjava التفاعلية غير قابلة للتغيير ؛ تُرجع كل من الطريقة التي تستدعيها Flowable
مع سلوك إضافي. لتوضيح ، يمكن إعادة كتابة المثال على النحو التالي:
Flowable < String > source = Flowable . fromCallable (() -> {
Thread . sleep ( 1000 ); // imitate expensive computation
return "Done" ;
});
Flowable < String > runBackground = source . subscribeOn ( Schedulers . io ());
Flowable < String > showForeground = runBackground . observeOn ( Schedulers . single ());
showForeground . subscribe ( System . out :: println , Throwable :: printStackTrace );
Thread . sleep ( 2000 );
عادةً ، يمكنك نقل الحسابات أو منع IO إلى مؤشر ترابط أخرى عبر subscribeOn
. بمجرد أن تكون البيانات جاهزة ، يمكنك التأكد من معالجتها على مؤشر ترابط المقدمة أو واجهة المستخدم الرسومية عبر observeOn
.
لا يعمل مشغلو RXJAVA مع Thread
S أو ExecutorService
مباشرة ، ولكن مع ما يسمى Scheduler
الذي يتجريد من مصادر التزامن وراء واجهة برمجة تطبيقات موحدة. يتميز Rxjava 3 بالعديد من المجدولات القياسية التي يمكن الوصول إليها عبر فئة Schedulers
الجدولية.
Schedulers.computation()
: قم بتشغيل عمل مكثف للحساب على عدد ثابت من المواضيع المخصصة في الخلفية. يستخدم معظم المشغلين غير المتزامنين هذا كمجدول Scheduler
.Schedulers.io()
: قم بتشغيل عمليات الإدخال/الإخراج أو الحظر على مجموعة من المواضيع المتغيرة ديناميكيًا.Schedulers.single()
: قم بتشغيل العمل على موضوع واحد بطريقة متتابعة و FIFO.Schedulers.trampoline()
: تشغيل العمل بطريقة متسلسلة و FIFO بطريقة واحدة من المواضيع المشاركة ، وعادة ما يكون لأغراض الاختبار. هذه متوفرة على جميع منصات JVM ولكن بعض المنصات المحددة ، مثل Android ، لها محددة من Scheduler
النموذجية: AndroidSchedulers.mainThread()
، SwingScheduler.instance()
أو JavaFXScheduler.platform()
.
بالإضافة إلى ذلك ، هناك خيار لفصل Executor
الحالي (وأنواعه الفرعية مثل ExecutorService
) في Scheduler
عبر Schedulers.from(Executor)
. يمكن استخدام هذا ، على سبيل المثال ، للحصول على مجموعة أكبر ولكن لا يزال ثابتًا من الخيوط (على عكس computation()
و io()
على التوالي).
Thread.sleep(2000);
في النهاية ليس مصادفة. في Rxjava ، يتم تشغيل Scheduler
S الافتراضي على مؤشرات الترابط الخفي ، مما يعني أنه بمجرد خروج مؤشر الترابط الرئيسي Java ، يتم إيقافهم جميعًا وقد لا تحدث حسابات الخلفية أبدًا. يتيح لك النوم لبعض الوقت في هذا المثال أن ترى إخراج التدفق على وحدة التحكم مع مرور الوقت لتجنيبها.
التدفقات في rxjava متتابعة في الطبيعة الانقسام إلى مراحل المعالجة التي قد تعمل بشكل متزامن مع بعضها البعض:
Flowable . range ( 1 , 10 )
. observeOn ( Schedulers . computation ())
. map ( v -> v * v )
. blockingSubscribe ( System . out :: println );
يتدفق هذا المثال ، يتراجع الأرقام من 1 إلى 10 على Scheduler
الحساب ويستهلك النتائج على الخيط "الرئيسي" (بشكل أدق ، مؤشر ترابط المتصل من blockingSubscribe
). ومع ذلك ، فإن Lambda v -> v * v
لا يعمل بالتوازي مع هذا التدفق ؛ يستقبل القيم من 1 إلى 10 على نفس مؤشر ترابط الحساب واحدًا تلو الآخر.
إن معالجة الأرقام من 1 إلى 10 بالتوازي أكثر مشاركة قليلاً:
Flowable . range ( 1 , 10 )
. flatMap ( v ->
Flowable . just ( v )
. subscribeOn ( Schedulers . computation ())
. map ( w -> w * w )
)
. blockingSubscribe ( System . out :: println );
من الناحية العملية ، يعني التوازي في rxjava تشغيل تدفقات مستقلة ودمج نتائجها مرة أخرى في تدفق واحد. يقوم المشغل flatMap
بذلك عن طريق رسم خرائط كل رقم من 1 إلى 10 إلى فرده Flowable
، ويديرها ودمج المربعات المحسوبة.
لاحظ ، مع ذلك ، أن flatMap
لا يضمن أي طلب وقد ينتهي الأمر بالعناصر من التدفقات الداخلية. هناك عوامل بديلة:
concatMap
الذي يقوم بتخطيط وتشغيل تدفق داخلي واحد في وقت واحد وconcatMapEager
الذي يدير جميع التدفقات الداخلية "في وقت واحد" ولكن تدفق الإخراج سيكون بالترتيب تم إنشاء تلك التدفقات الداخلية. بدلاً من ذلك ParallelFlowable
يساعد المشغل Flowable.parallel()
.
Flowable . range ( 1 , 10 )
. parallel ()
. runOn ( Schedulers . computation ())
. map ( v -> v * v )
. sequential ()
. blockingSubscribe ( System . out :: println );
flatMap
هو عامل قوي ويساعد في الكثير من المواقف. على سبيل المثال ، بالنظر إلى خدمة تُرجع Flowable
، نود الاتصال بخدمة أخرى بقيم تنبعث من الخدمة الأولى:
Flowable < Inventory > inventorySource = warehouse . getInventoryAsync ();
inventorySource
. flatMap ( inventoryItem -> erp . getDemandAsync ( inventoryItem . getId ())
. map ( demand -> "Item " + inventoryItem . getName () + " has demand " + demand ))
. subscribe ( System . out :: println );
في بعض الأحيان ، عندما يصبح عنصر ما متاحًا ، يرغب المرء في إجراء بعض الحسابات المعتمدة عليه. ويسمى هذا في بعض الأحيان الاستمرارية ، واعتمادًا على ما يجب أن يحدث وما هي الأنواع المتورطة ، قد تشمل العديد من المشغلين لإنجازها.
السيناريو الأكثر نموذجية هو إعطاء قيمة ، واستدعاء خدمة أخرى ، وانتظار ومتابعة نتائجها:
service . apiCall ()
. flatMap ( value -> service . anotherApiCall ( value ))
. flatMap ( next -> service . finalCall ( next ))
غالبًا ما تتطلب التسلسلات اللاحقة قيمًا من التعيينات السابقة. يمكن تحقيق ذلك عن طريق تحريك flatMap
الخارجية إلى الأجزاء الداخلية من flatMap
السابقة على سبيل المثال:
service . apiCall ()
. flatMap ( value ->
service . anotherApiCall ( value )
. flatMap ( next -> service . finalCallBoth ( value , next ))
)
هنا ، ستكون value
الأصلية متوفرة داخل flatMap
الداخلية ، بإذن من Lambda Variable Capture.
في السيناريوهات الأخرى ، تكون نتائج (نتائج) المصدر/تدفق البيانات الأول غير ذي صلة ويود المرء أن يستمر مع مصدر آخر شبه مستقل. هنا ، يعمل flatMap
أيضًا:
Observable continued = sourceObservable . flatMapSingle ( ignored -> someSingleSource )
continued . map ( v -> v . toString ())
. subscribe ( System . out :: println , Throwable :: printStackTrace );
ومع ذلك ، فإن الاستمرار في هذه الحالة يبقى Observable
بدلاً من Single
الأكثر ملاءمة. (هذا أمر مفهوم لأنه من منظور flatMapSingle
، sourceObservable
هو مصدر متعدد القيمة ، وبالتالي قد يؤدي التعيين إلى قيم متعددة أيضًا).
في كثير من الأحيان ، على الرغم من أن هناك طريقة أكثر تعبيرية (وأيضًا أقل من النفقات العامة) باستخدام Completable
مثل الوسيط ومشغله andThen
مع شيء آخر:
sourceObservable
. ignoreElements () // returns Completable
. andThen ( someSingleSource )
. map ( v -> v . toString ())
التبعية الوحيدة بين sourceObservable
و someSingleSource
هي أن الأول يجب أن يكمل بشكل طبيعي حتى يتم استهلاك الأخير.
في بعض الأحيان ، هناك اعتماد ضمني على البيانات بين التسلسل السابق والتسلسل الجديد الذي لم يكن يتدفق ، لسبب ما ، عبر "القنوات العادية". يميل المرء إلى كتابة مثل هذه الاستمرارات كما يلي:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . just ( count . get ()))
. subscribe ( System . out :: println );
لسوء الحظ ، يطبع هذا 0
لأنه يتم تقييم Single.just(count.get())
في وقت التجميع عندما لم يتم تشغيل تدفق البيانات حتى الآن. نحتاج إلى شيء يثير تقييم هذا المصدر Single
حتى وقت التشغيل عند اكتمال المصدر الرئيسي:
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . defer (() -> Single . just ( count . get ())))
. subscribe ( System . out :: println );
أو
AtomicInteger count = new AtomicInteger ();
Observable . range ( 1 , 10 )
. doOnNext ( ignored -> count . incrementAndGet ())
. ignoreElements ()
. andThen ( Single . fromCallable (() -> count . get ()))
. subscribe ( System . out :: println );
في بعض الأحيان ، تُرجع المصدر أو الخدمة نوعًا مختلفًا عن التدفق الذي من المفترض أن يعمل معه. على سبيل المثال ، في مثال المخزون أعلاه ، يمكن getDemandAsync
إرجاع Single<DemandRecord>
. إذا تم ترك مثال الكود دون تغيير ، فسيؤدي ذلك إلى خطأ في وقت الترجمة (ومع ذلك ، غالبًا ما يكون هناك رسالة خطأ مضللة حول عدم الحمل الزائد).
في مثل هذه الحالات ، عادة ما يكون هناك خياران لإصلاح التحول: 1) التحويل إلى النوع المطلوب أو 2) ابحث عن الحمل الزائد للمشغل المحدد الذي يدعم النوع مختلف.
تتميز كل فئة من فئة الفئة التفاعلية التي يمكنها إجراء مثل هذه التحويلات ، بما في ذلك تحويلات البروتوكول ، لمطابقة نوع آخر. تعرض المصفوفة التالية خيارات التحويل المتاحة:
قابل للتدفق | يمكن ملاحظته | أعزب | ربما | قابلية الانتهاء | |
---|---|---|---|---|---|
قابل للتدفق | toObservable | first ، firstOrError ، single ، singleOrError ، last ، lastOrError 1 | firstElement ، singleElement ، lastElement | ignoreElements | |
يمكن ملاحظته | toFlowable 2 | first ، firstOrError ، single ، singleOrError ، last ، lastOrError 1 | firstElement ، singleElement ، lastElement | ignoreElements | |
أعزب | toFlowable 3 | toObservable | toMaybe | ignoreElement | |
ربما | toFlowable 3 | toObservable | toSingle | ignoreElement | |
قابلية الانتهاء | toFlowable | toObservable | toSingle | toMaybe |
1 : عند تحويل مصدر متعدد القيم إلى مصدر ذي قيمة واحدة ، ينبغي للمرء أن يقرر أي من قيم المصدر العديدة التي يجب اعتبارها نتيجة.
2 : يتطلب تحويل Observable
إلى Flowable
قرارًا إضافيًا: ماذا تفعل مع التدفق غير المقيد المحتمل للمصدر Observable
؟ هناك العديد من الاستراتيجيات المتوفرة (مثل التخزين المؤقت ، والتخفيض ، والاحتفاظ بالأحدث) عبر معلمة BackpressureStrategy
أو عن طريق عواملهم القياسية Flowable
مثل onBackpressureBuffer
، onBackpressureDrop
، و onBackpressureLatest
والتي تسمح أيضًا بتخصيص سلوك الظهر.
3 : عندما يكون هناك عنصر مصدر واحد فقط (على الأكثر) ، لا توجد مشكلة في الضغط على الظهر لأنه يمكن تخزينه دائمًا حتى يصبح المجلس جاهزًا للاستهلاك.
العديد من المشغل المستخدمة بشكل متكرر لديه أحمال زائدة يمكن أن تتعامل مع الأنواع الأخرى. عادة ما يتم تسمية هذه مع لاحقة النوع المستهدف:
المشغل | الأحمال الزائدة |
---|---|
flatMap | flatMapSingle ، flatMapMaybe ، flatMapCompletable ، flatMapIterable |
concatMap | concatMapSingle ، concatMapMaybe ، concatMapCompletable ، concatMapIterable |
switchMap | switchMapSingle ، switchMapMaybe ، switchMapCompletable |
السبب في أن هؤلاء المشغلين لديهم لاحقة بدلاً من مجرد الحصول على نفس الاسم بتوقيع مختلف هو محو النوع. لا تنظر Java في توقيعات مثل operator(Function<T, Single<R>>)
operator(Function<T, Maybe<R>>)
مختلفة (على عكس C#) وبسبب المحو ، سينتهي operator
s كطرق مكررة مع نفس التوقيع.
يعد التسمية في البرمجة واحدة من أصعب الأشياء حيث من المتوقع أن تكون الأسماء طويلة ، أو تعبيرية ، وتلتقطها ولا تنسى بسهولة. لسوء الحظ ، قد لا تقدم اللغة المستهدفة (والاتفاقيات الموجودة مسبقًا) الكثير من المساعدة في هذا الصدد (الكلمات الرئيسية غير القابلة للاستعمال ، ومحو النوع ، والكتب الغموض ، وما إلى ذلك).
في RX.NET الأصلي ، يسمى المشغل الذي ينبعث منه عنصرًا واحدًا ثم يكمله Return(T)
. نظرًا لأن اتفاقية Java يجب أن يكون لها حرف صغير ، فستبدأ اسم طريقة ، وكان هذا هو return(T)
وهي كلمة رئيسية في Java وبالتالي غير متوفرة. لذلك ، اختار Rxjava تسمية هذا المشغل just(T)
. يوجد نفس القيد Switch
المشغل ، والذي كان لا بد من تسمية switchOnNext
. مثال آخر هو Catch
الذي سمي onErrorResumeNext
.
لا يمكن تحميل العديد من المشغلين الذين يتوقعون من المستخدم توفير بعض الوظائف التي تعيد نوعًا تفاعليًا لأن نوع محو النوع حول Function<T, X>
يحول توقيعات هذه الطريقة إلى التكرارات. اختارت Rxjava تسمية هؤلاء المشغلين من خلال إلحاق النوع باسم لاحقة أيضًا:
Flowable < R > flatMap ( Function <? super T , ? extends Publisher <? extends R >> mapper )
Flowable < R > flatMapMaybe ( Function <? super T , ? extends MaybeSource <? extends R >> mapper )
على الرغم من أن بعض المشغلين ليس لديهم أي مشاكل من محو النوع ، إلا أن توقيعهم قد يظهر غامضة ، خاصة إذا كان الشخص يستخدم Java 8 و Lambdas. على سبيل المثال ، هناك العديد من الأحمال الزائدة من concatWith
مع مختلف أنواع القاعدة التفاعلية الأخرى كوسيطات (لتوفير فوائد الراحة والأداء في التنفيذ الأساسي):
Flowable < T > concatWith ( Publisher <? extends T > other );
Flowable < T > concatWith ( SingleSource <? extends T > other );
يظهر كل من Publisher
SingleSource
كواجهات وظيفية (أنواع ذات طريقة مجردة واحدة) وقد تشجع المستخدمين على محاولة تقديم تعبير Lambda:
someSource . concatWith ( s -> Single . just ( 2 ))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
لسوء الحظ ، هذا النهج لا يعمل والمثال لا يطبع 2
على الإطلاق. في الواقع ، نظرًا لأن الإصدار 2.1.10 ، فإنه لا يجمع حتى لأن 4 concatWith
على الأقل موجودة مع وجود الأحمال الزائدة ويجد المترجم الكود أعلاه غامضًا.
ربما أراد المستخدم في مثل هذه المواقف تأجيل بعض الحسابات حتى يكتمل someSource
، وبالتالي كان ينبغي أن يكون المشغل الصحيح غير المبين defer
:
someSource . concatWith ( Single . defer (() -> Single . just ( 2 )))
. subscribe ( System . out :: println , Throwable :: printStackTrace );
في بعض الأحيان ، تتم إضافة اللاحقة لتجنب الغموض المنطقي الذي قد يتم تجميعه ولكنه ينتج النوع الخطأ في التدفق:
Flowable < T > merge ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > mergeArray ( Publisher <? extends T >... sources );
يمكن أن يصبح هذا أيضًا غامضًا عندما تتورط أنواع الواجهة الوظيفية كوسيطة نوع T
يمكن أن تفشل تدفقات البيانات ، عند هذه النقطة ، ينبعث الخطأ إلى المستهلك (المستهلكين). في بعض الأحيان ، قد تفشل مصادر متعددة عند هذه النقطة ، حيث يوجد خيار ما إذا كان ينتظر كل منهم لإكماله أو عدم إكماله أم لا. للإشارة إلى هذه الفرصة ، يتم اللاحقة للعديد من أسماء المشغلين بكلمات DelayError
(بينما يتميز الآخرون بعلم delayError
أو delayErrors
في أحد الأحمال الزائدة):
Flowable < T > concat ( Publisher <? extends Publisher <? extends T >> sources );
Flowable < T > concatDelayError ( Publisher <? extends Publisher <? extends T >> sources );
بالطبع ، قد تظهر اللواحق من أنواع مختلفة معًا:
Flowable < T > concatArrayEagerDelayError ( Publisher <? extends T >... sources );
يمكن اعتبار فئات الأساس ثقيلة بسبب العدد الهائل من أساليب مثيل ثابتة عليها. تأثر تصميم Rxjava 3 بشدة بمواصفات التدفقات التفاعلية ، وبالتالي ، تتميز المكتبة بفئة وواجهة لكل نوع تفاعلي:
يكتب | فصل | واجهة | مستهلك |
---|---|---|---|
0.. إن الظهر | Flowable | Publisher 1 | Subscriber |
0..N غير محدود | Observable | ObservableSource 2 | Observer |
عنصر واحد أو خطأ | Single | SingleSource | SingleObserver |
0..1 عنصر أو خطأ | Maybe | MaybeSource | MaybeObserver |
0 عنصر أو خطأ | Completable | CompletableSource | CompletableObserver |
1 org.reactivestreams.Publisher
هو جزء من مكتبة التدفقات التفاعلية الخارجية. هذا هو النوع الرئيسي للتفاعل مع المكتبات التفاعلية الأخرى من خلال آلية موحدة تحكمها مواصفات التدفقات التفاعلية.
2 كانت اتفاقية التسمية للواجهة لإلحاق Source
إلى اسم الفصل شبه التقليدي. لا يوجد أي FlowableSource
حيث يتم توفير Publisher
من قبل مكتبة التدفقات التفاعلية (والوسطى الفرعي لم يكن من الممكن أن يساعد في interoperation أيضًا). ومع ذلك ، فإن هذه الواجهات ليست قياسية بمعنى مواصفات التدفقات التفاعلية وهي حاليًا محددة Rxjava فقط.
بشكل افتراضي ، لا يتطلب Rxjava نفسها أي إعدادات بروغ/R8 ويجب أن تعمل بدون مشاكل. لسوء الحظ ، فإن تبعية التدفقات التفاعلية منذ الإصدار 1.0.3 قد دمج ملفات فئة Java 9 في جرةها والتي يمكن أن تسبب تحذيرات مع proguard العادي:
Warning: org.reactivestreams.FlowAdapters$FlowPublisherFromReactive: can't find superclass or interface java.util.concurrent.Flow$Publisher
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveProcessor: can't find superclass or interface java.util.concurrent.Flow$Processor
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscriber: can't find superclass or interface java.util.concurrent.Flow$Subscriber
Warning: org.reactivestreams.FlowAdapters$FlowToReactiveSubscription: can't find superclass or interface java.util.concurrent.Flow$Subscription
Warning: org.reactivestreams.FlowAdapters: can't find referenced class java.util.concurrent.Flow$Publisher
يوصى بإعداد إدخال -dontwarn
التالي في ملف proguard-ruleset
الخاص بالتطبيق:
-dontwarn java.util.concurrent.Flow*
بالنسبة إلى R8 ، تتضمن جرة RXJAVA META-INF/proguard/rxjava3.pro
لمزيد من التفاصيل ، استشر الويكي.
الإصدار 3.x قيد التطوير. سيتم تطبيق مجموعات Bughfixes على كل من فروع 2.x و 3.x ، ولكن سيتم إضافة ميزات جديدة فقط إلى 3.x.
ستحدث زيادات 3.x ثانوية (مثل 3.1 ، 3.2 ، إلخ) عند إضافة وظائف جديدة غير تافهة أو تحدث تحسينات كبيرة أو إصلاحات الأخطاء التي قد تكون لها تغييرات سلوكية قد تؤثر على بعض حالات الحافة (مثل الاعتماد على السلوك الناتج عن السلوك الناتج عن السلوك علة). مثال على التعزيز الذي من شأنه أن يصنف لأن هذا يضيف دعم ضغط الظهر التفاعلي للمشغل الذي لم يدعمه سابقًا. يجب أن يكون هذا متوافقًا للخلف ولكنه يتصرف بشكل مختلف.
تصحيح 3. زيادات (مثل 3.0.0 -> 3.0.1 ، 3.3.1 -> 3.3.2 ، إلخ) ستحدث لإصلاحات الأخطاء والوظائف التافهة (مثل إضافة طريقة زائدة من الطريقة). يمكن أيضًا إضافة وظائف جديدة تتميز بتوضيح @Beta
@Experimental
في إصدارات التصحيح للسماح بالاستكشاف السريع وتكرار وظائف جديدة غير مستقرة.
واجهات برمجة التطبيقات التي تحمل علامة التعليقات التوضيحية @Beta
في الفصل أو مستوى الطريقة تخضع للتغيير. يمكن تعديلها بأي شكل من الأشكال ، أو حتى إزالتها ، في أي وقت. إذا كانت الكود الخاص بك عبارة عن مكتبة بحد ذاتها (أي يتم استخدامها على فئة المستخدمين خارج نطاق التحكم) ، فيجب ألا تستخدم APIs Beta ، إلا إذا قمت بإعادة تعبئتها (على سبيل المثال باستخدام Proguard ، التظليل ، إلخ).
من المؤكد أن واجهات برمجة التطبيقات التي تحمل علامة التعليق @Experimental
في الفصل أو مستوى الطريقة ستتغير. يمكن تعديلها بأي شكل من الأشكال ، أو حتى إزالتها ، في أي وقت. يجب ألا تستخدم أو تعتمد عليها في أي رمز إنتاج. هم بحتة للسماح للاختبار والتعليقات الواسعة.
سيظل واجهات برمجة التطبيقات المميزة بالتعليقات التوضيحية @Deprecated
في الفصل أو مستوى الطريقة مدعومة حتى الإصدار الرئيسي التالي ، ولكن يوصى بالتوقف عن استخدامها.
جميع التعليمات البرمجية داخل io.reactivex.rxjava3.internal.*
تعتبر الحزم واجهة برمجة تطبيقات خاصة ولا ينبغي الاعتماد عليها على الإطلاق. يمكن أن يتغير في أي وقت.
http://reactivex.io/RxJava/3.x/javadoc/3.xy/
يمكن العثور على الثنائيات ومعلومات التبعية لـ Maven و Ivy و Gradle وغيرها على http://search.maven.org.
مثال على Gradle:
implementation ' io.reactivex.rxjava3:rxjava:x.y.z '
وللمين:
< dependency >
< groupId >io.reactivex.rxjava3</ groupId >
< artifactId >rxjava</ artifactId >
< version >x.y.z</ version >
</ dependency >
وللبلاب:
< dependency org = " io.reactivex.rxjava3 " name = " rxjava " rev = " x.y.z " />
تتوفر لقطات بعد الأول من مايو ، 2021 عبر https://oss.sonatype.org/content/repositories/snapshots/io/reactivex/rxjava3/rxjava/
repositories {
maven { url ' https://oss.sonatype.org/content/repositories/snapshots ' }
}
dependencies {
implementation ' io.reactivex.rxjava3:rxjava:3.0.0-SNAPSHOT '
}
تتوفر لقطات Javadoc على http://reactivex.io/rxjava/3.x/javadoc/snapshot
للبناء:
$ git clone [email protected]:ReactiveX/RxJava.git
$ cd RxJava/
$ ./gradlew build
يمكن العثور على مزيد من التفاصيل حول المبنى على صفحة البدء في الويكي.
بالنسبة للأخطاء والأسئلة والمناقشات ، يرجى استخدام مشكلات جيثب.
Copyright (c) 2016-present, RxJava Contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.