در بحث کوروتین ها با توابع suspend آشنا شده ایم, این توابع یک مقدار بازگشتی را بصورت async برگردانی میکنند. اما چگونه میتوانیم کاری کنیم تا چندین مقدار توسط این توابع بازگشت داده شود؟ بله در این زمان باید از ویژگی به اسم Flow در زبان برنامه نویسی کاتلین استفاده کنیم.
Flow یک روش پردازش استریم ها که توسط کمپانی Jetbrain توسعه داده شده است و در دسته بندی برنامه نویسی Reactive قرار میگیرد. هدف این کار پردازش استریم ها به شکلی ناهمگام بود.با استفاده از قابلیت های Flow برای مدیریت مقادیر استریم ها میتوانید اطلاعات را با استفاده از راه های مالتی تردینگ به اشکال پیچیده تر تبدیل کنید و این کار فقط با کدنویسی چند خط ساده امکان پذیر است.یکی از مزایای خوب Flow ها این است که فقط زمانی اجرا میشوند که یک observer یک متد یا عملگری تعلیق کننده ( suspend) مثل collect را صدا بزند و بعد از آن دیگر فعال نمیماند. برای شروع ابتدا کتابخانه های زیر را باید وارد پروژده کنید.
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
همچنین پلاگین زیر:
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
در صفحه اکتیویتی یک رابط کاربری با کدهای زیر ایجاد میکنیم.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:text="Launch Kotlin Flow"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
در کدهای کاتلین و متد onCreate() دو متد زیر را فراخوانی میکنیم و سپس به پیاده سازی آنها میپردازیم.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupFlow()
setupClicks()
}
در متد setupFlow() کدهای مربوط به پیاده سازی Flow را قرار میدهیم و در متد setupClicks() با کلیک کردن روی دکمه اطلاعات مورد نظر را نمایش میدهیم.
قبل از این موارد یک متغیر از نوع int نیز تعریف میکنیم.
lateinit var flow: Flow<Int>
در متد setupFlow اعداد را از 0 تا 10 با 500 میلی ثانیه تاخیر بین هرکدام ارسال میکنیم.
fun setupFlow(){
flow = flow {
Log.d(TAG, "Start flow")
(0..10).forEach {
// Emit items with 500 milliseconds delay
delay(500)
Log.d(TAG, "Emitting $it")
emit(it)
}
}.flowOn(Dispatchers.Default)
}
این کار توسط تابع emit() انجام می شود که وظیفه آن جمع آوری اطلاعات ارسال شده است و بخشی از FlowCollector می باشد.
در آخر هم از flowOn استفاده میکنیم نوع Dispatchers را مشخص میکند مانند IO, Default و...
flowOn تقریبا مثل تابع subscribeOn در RXJava است.
در متد setupClicks() نیاز داریم تا رویداد کلیک را بنویسیم و مقادیر منتشر شده را نمایش دهیم.
private fun setupClicks() {
button.setOnClickListener {
CoroutineScope(Dispatchers.Main).launch {
flow.collect {
Log.d(TAG, it.toString())
}
}
}
}
با کلیک کردن روی دکمه مقادیر یک به یک نمایش داده خواهد شد.
دستور flow.collect شروع به جمع آوری اطلاعات از Flow میکند.
خروجی نهایی بعد از کلیک کردن روی دکمه به شکل زیر است:
D/MainActivity: Start flow
D/MainActivity: Emitting 0
D/MainActivity: 0
D/MainActivity: Emitting 1
D/MainActivity: 1
D/MainActivity: Emitting 2
D/MainActivity: 2
D/MainActivity: Emitting 3
D/MainActivity: 3
D/MainActivity: Emitting 4
D/MainActivity: 4
D/MainActivity: Emitting 5
D/MainActivity: 5
D/MainActivity: Emitting 6
D/MainActivity: 6
D/MainActivity: Emitting 7
D/MainActivity: 7
D/MainActivity: Emitting 8
D/MainActivity: 8
D/MainActivity: Emitting 9
D/MainActivity: 9
D/MainActivity: Emitting 10
D/MainActivity: 10
همانطور که میبینید Flow درست زمانی شروع میشود که روی دکمه کلیک میکنیم و پیغام Start Flow نمایش داده میشود.
این همان ویژگی جالبی است که بالاتر به آن اشاره کردیم.
حالا قصد داریم تا کمی تغییرات در کدهای خودمون ایجاد کنیم.
در تصویر بالا میبینید که دستور map را اضافه کردیم و هر آیتم را در خود ضرب کنیم یا به توان دو میرسانیم.
private fun setupFlow() {
flow = flow {
Log.d(TAG, "Start flow")
(0..10).forEach {
// Emit items with 500 milliseconds delay
delay(500)
Log.d(TAG, "Emitting $it")
emit(it)
}
}.map {
it * it
}.flowOn(Dispatchers.Default)
}
تمام دستوراتی که بالای flowOn نوشته میشوند در ترید پس زمینه اجرا میشوند.
برای Flow ها یک سری امکانات دیگر نیز در نظر گرفته شده مثل Builderها که باهم بررسی میکنیم.
زمانی که بخواهیم از یک سری مجموعه اطلاعات ثابت استفاده کنیم دستور flowOf() به کمک ما می آید.
flowOf(4, 2, 5, 1, 7).onEach { delay(400) }.flowOn(Dispatcher.Default)
دستور asFlow() به ما این امکان را میدهد تا دیتا تایپ ها را به Flow تبدیل کنیم.
(1..5).asFlow().onEach{ delay(300)}.flowOn(Dispatchers.Default)
در این مثال یک مقدار رنج از 1 تا 5 را به Flow تبدیل کردیم.
یادگیری برنامه نویسی برای متخصصین حوزه کامپیوتر این روزها یک الزام به حساب می آید. از جمله محبوب ترین زبان های برنامه نویسی دنیا می توانیم به زبان برنامه نویسی سی شارپ ، زبان برنامه نویسی جاوا ، زبان برنامه نویسی پایتون ، زبان برنامه نویسی سی پلاس پلاس و زبان برنامه نویسی SQL ( لازمه هر زبان دیگری ) و زبان برنامه نویسی PHP اشاره کنیم.
برای آموزش برنامه نویسی می توانید با خیال راحت در قالب دوره های آموزش برنامه نویسی سایت توسینسو ، آموزش سی شارپ ، آموزش جاوا ، آموزش پایتون ، آموزش جنگو ، آموزش PHP ، آموزش جاوا اسکریپت ، آموزش برنامه نویسی اندروید ، آموزش SQL و آموزش MySQL را بصورت جامع و حرفه ای آموزش ببینید.
برنامه نویس موبایل
کارشناسی فناوری اطلاعات برنامه نویس موبایل با زبان های جاوا, کاتلین, دارت(فلاتر) CCNA,LPIC
زمان پاسخ گویی روز های شنبه الی چهارشنبه ساعت 9 الی 18
فقط به موضوعات مربوط به محصولات آموزشی و فروش پاسخ داده می شود