راهنمای شروع کار نحوه ایجاد یک WorkRequest
ساده و در صف قرار دادن آن را توضیح می دهد.
در این راهنما، نحوه تعریف و سفارشی کردن اشیاء WorkRequest
برای رسیدگی به موارد استفاده رایج، مانند نحوه انجام موارد زیر را خواهید آموخت:
- برای کارهای یکباره و مکرر برنامه ریزی کنید
- محدودیتهای کاری مانند نیاز به Wi-Fi یا شارژ را تنظیم کنید
- تضمین حداقل تاخیر در اجرای کار
- راهبردهای تلاش مجدد و عقب نشینی را تنظیم کنید
- داده های ورودی را به کار منتقل کنید
- کارهای مرتبط را با هم با استفاده از برچسب ها گروه بندی کنید
نمای کلی
کار در WorkManager از طریق WorkRequest
تعریف می شود. برای زمانبندی هر کاری با WorkManager، ابتدا باید یک شی WorkRequest
ایجاد کنید و سپس آن را در صف قرار دهید.
کاتلین
val myWorkRequest = ... WorkManager.getInstance(myContext).enqueue(myWorkRequest)
جاوا
WorkRequest myWorkRequest = ... WorkManager.getInstance(myContext).enqueue(myWorkRequest);
شی WorkRequest شامل تمام اطلاعات مورد نیاز WorkManager برای برنامه ریزی و اجرای کار شما می باشد. این شامل محدودیتهایی است که برای اجرای کار شما باید رعایت شوند، اطلاعات زمانبندی مانند تأخیر یا تکرار فواصل، پیکربندی مجدد، و ممکن است شامل دادههای ورودی باشد، اگر کار شما به آن متکی باشد.
WorkRequest
خود یک کلاس پایه انتزاعی است. دو پیاده سازی مشتق شده از این کلاس وجود دارد که می توانید از آنها برای ایجاد درخواست استفاده کنید، OneTimeWorkRequest
و PeriodicWorkRequest
. همانطور که از نام آنها پیداست، OneTimeWorkRequest
برای برنامه ریزی کارهای غیر تکراری مفید است، در حالی که PeriodicWorkRequest
برای برنامه ریزی کاری که در فواصل زمانی تکرار می شود مناسب تر است.
برای کار یکباره برنامه ریزی کنید
برای کارهای ساده، که نیازی به پیکربندی اضافی ندارد، from
روش استاتیک استفاده کنید:
کاتلین
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)
جاوا
WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);
برای کارهای پیچیده تر، می توانید از یک سازنده استفاده کنید:
کاتلین
val uploadWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<MyWork>() // Additional configuration .build()
جاوا
WorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) // Additional configuration .build();
کار تسریع شده را برنامه ریزی کنید
WorkManager 2.7.0 مفهوم کار تسریع شده را معرفی کرد. این به WorkManager اجازه می دهد تا کارهای مهم را اجرا کند در حالی که به سیستم کنترل بهتری بر دسترسی به منابع می دهد.
کار تسریع شده به دلیل ویژگی های زیر قابل توجه است:
- اهمیت : کار تسریع شده متناسب با وظایفی است که برای کاربر مهم هستند یا توسط کاربر شروع شده اند.
- سرعت : کار تسریع شده به بهترین وجه با کارهای کوتاهی که بلافاصله شروع می شوند و در عرض چند دقیقه تکمیل می شوند، مناسب است.
- سهمیه ها : سهمیه ای در سطح سیستم که زمان اجرای پیش زمینه را محدود می کند، تعیین می کند که آیا یک کار تسریع شده می تواند شروع شود یا خیر.
- مدیریت انرژی : محدودیتهای مدیریت انرژی ، مانند Battery Saver و Doze، کمتر بر سرعت کار تأثیر میگذارند.
- تأخیر : سیستم فوراً کار تسریع شده را اجرا می کند، مشروط بر اینکه بار کاری فعلی سیستم آن را قادر به انجام این کار کند. این بدان معنی است که آنها به تأخیر حساس هستند و نمی توان آنها را برای اجرای بعدی برنامه ریزی کرد.
زمانی که کاربر میخواهد پیام یا تصویر پیوستی ارسال کند، یک مورد استفاده بالقوه برای کار سریع ممکن است در یک برنامه چت باشد. به طور مشابه، برنامهای که جریان پرداخت یا اشتراک را مدیریت میکند ممکن است بخواهد از کار تسریع شده استفاده کند. این به این دلیل است که آن وظایف برای کاربر مهم هستند، به سرعت در پسزمینه اجرا میشوند، باید فوراً شروع شوند و حتی اگر کاربر برنامه را ببندد، باید اجرا شوند.
سهمیه ها
سیستم باید قبل از اجرای آن، زمان اجرا را به یک کار تسریع شده اختصاص دهد. زمان اجرا نامحدود نیست. در عوض، هر برنامه سهمیه ای از زمان اجرا را دریافت می کند. وقتی برنامه شما از زمان اجرای خود استفاده می کند و به سهمیه اختصاص داده شده خود می رسد، تا زمانی که سهمیه بازخوانی نشود، دیگر نمی توانید کار تسریع شده را اجرا کنید. این به اندروید اجازه می دهد تا به طور موثرتری منابع بین برنامه ها را متعادل کند.
مقدار زمان اجرا در دسترس برای یک برنامه بر اساس سطل آماده به کار و اهمیت فرآیند است.
شما می توانید تعیین کنید که وقتی سهمیه اجرا اجازه نمی دهد تا یک کار تسریع شده بلافاصله اجرا شود چه اتفاقی می افتد. برای جزئیات بیشتر به بخش های زیر مراجعه کنید.
اجرای کار تسریع شده
با شروع در WorkManager 2.7، برنامه شما می تواند setExpedited()
را فراخوانی کند تا اعلام کند که WorkRequest
باید در سریع ترین زمان ممکن با استفاده از یک کار تسریع شده اجرا شود. قطعه کد زیر نمونه ای از نحوه استفاده از setExpedited()
را ارائه می دهد:
کاتلین
val request = OneTimeWorkRequestBuilder<SyncWorker>() .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build() WorkManager.getInstance(context) .enqueue(request)
جاوا
OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>() .setInputData(inputData) .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .build();
در این مثال، یک نمونه از OneTimeWorkRequest
را مقداردهی اولیه کرده و setExpedited()
روی آن فراخوانی می کنیم. سپس این درخواست تبدیل به کار تسریع شده می شود. اگر سهمیه اجازه دهد، بلافاصله در پسزمینه اجرا میشود. اگر از سهمیه استفاده شده باشد، پارامتر OutOfQuotaPolicy
نشان میدهد که درخواست باید بهعنوان کار عادی و بدون سرعت اجرا شود.
سازگاری با پیش زمینه و خدمات پیش زمینه
برای حفظ سازگاری به عقب برای کارهای سریع، WorkManager ممکن است یک سرویس پیش زمینه را در نسخه های پلتفرم قدیمی تر از Android 12 اجرا کند. سرویس های پیش زمینه می توانند اعلان را به کاربر نمایش دهند.
متدهای getForegroundInfoAsync()
و getForegroundInfo()
در Worker شما، WorkManager را قادر میسازد تا هنگام فراخوانی setExpedited()
قبل از Android 12 یک اعلان نمایش دهد.
هر ListenableWorker
باید متد getForegroundInfo
پیادهسازی کند اگر بخواهید کار را بهعنوان یک کار تسریع شده اجرا کنید.
هنگام هدف قرار دادن Android 12 یا بالاتر، خدمات پیش زمینه از طریق روش setForeground
مربوطه در دسترس شما باقی می ماند.
کارگر
کارگران نمی دانند که آیا کاری که انجام می دهند تسریع شده است یا خیر. اما کارگران می توانند در برخی از نسخه های Android هنگامی که درخواست WorkRequest
تسریع شده است، یک اعلان نمایش دهند.
برای فعال کردن این کار، WorkManager متد getForegroundInfoAsync()
را ارائه میکند که باید آن را پیادهسازی کنید تا WorkManager بتواند در صورت لزوم یک اعلان برای راهاندازی یک ForegroundService
برای شما نمایش دهد.
CoroutineWorker
اگر از CoroutineWorker
استفاده می کنید، باید getForegroundInfo()
پیاده سازی کنید. سپس آن را به setForeground()
درون doWork()
ارسال می کنید. با انجام این کار، اعلان در نسخه های اندروید قبل از 12 ایجاد می شود.
به مثال زیر توجه کنید:
class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
CoroutineWorker(appContext, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID, createNotification()
)
}
override suspend fun doWork(): Result {
TODO()
}
private fun createNotification() : Notification {
TODO()
}
}
سیاست های سهمیه بندی
میتوانید کنترل کنید که وقتی برنامه شما به سهمیه اجرای خود برسد، چه اتفاقی برای کار سریع میافتد. برای ادامه، می توانید setExpedited()
را ارسال کنید:
-
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST
، که باعث می شود کار به عنوان یک درخواست کاری معمولی اجرا شود. قطعه بالا این را نشان می دهد. -
OutOfQuotaPolicy.DROP_WORK_REQUEST
، که باعث می شود در صورت نبود سهمیه کافی، درخواست لغو شود.
نمونه برنامه
برای مشاهده یک مثال کامل از نحوه استفاده WorkManager 2.7.0 از کار سریع، به WorkManagerSample در GitHub نگاه کنید.
کار تسریع شده به تعویق افتاد
سیستم سعی می کند تا یک کار تسریع شده را در اسرع وقت پس از فراخوانی کار اجرا کند. با این حال، مانند سایر انواع مشاغل، سیستم ممکن است شروع کار سریع جدید را به تعویق بیندازد، مانند موارد زیر:
- بارگذاری : بار سیستم خیلی زیاد است، که ممکن است زمانی رخ دهد که تعداد زیادی کار در حال اجرا هستند، یا زمانی که سیستم حافظه کافی ندارد.
- سهمیه : از سقف سهمیه شغلی تسریع شده فراتر رفته است. کار تسریع شده از یک سیستم سهمیه استفاده میکند که مبتنی بر سطلهای آماده به کار برنامه است و حداکثر زمان اجرا را در یک پنجره زمانی متحرک محدود میکند. سهمیه هایی که برای کارهای تسریع شده استفاده می شود محدودتر از سهمیه هایی است که برای انواع دیگر مشاغل پس زمینه استفاده می شود.
کار دوره ای را برنامه ریزی کنید
برنامه شما ممکن است گاهی نیاز داشته باشد که کارهای خاصی به صورت دوره ای اجرا شود. برای مثال، ممکن است بخواهید به طور دورهای از دادههای خود نسخه پشتیبان تهیه کنید، محتوای تازه را در برنامه خود بارگیری کنید، یا گزارشها را در سرور آپلود کنید.
در اینجا نحوه استفاده از PeriodicWorkRequest
برای ایجاد یک شی WorkRequest
است که به صورت دوره ای اجرا می شود:
کاتلین
val saveRequest = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS) // Additional configuration .build()
جاوا
PeriodicWorkRequest saveRequest = new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS) // Constraints .build();
در این مثال کار با فاصله زمانی یک ساعت برنامه ریزی شده است.
بازه زمانی به عنوان حداقل زمان بین تکرارها تعریف می شود. زمان دقیقی که کارگر قرار است اجرا شود به محدودیت هایی که در شی WorkRequest خود استفاده می کنید و بهینه سازی های انجام شده توسط سیستم بستگی دارد.
فواصل دویدن انعطاف پذیر
اگر ماهیت کار شما به زمانبندی اجرا حساس است، میتوانید PeriodicWorkRequest
خود را طوری پیکربندی کنید که در یک دوره انعطافپذیر در هر بازه زمانی اجرا شود، همانطور که در شکل 1 نشان داده شده است.
شکل 1. نمودار فواصل تکرار شونده را با دوره انعطاف پذیر نشان می دهد که در آن کار می تواند اجرا شود.
برای تعریف کار دورهای با دوره انعطافپذیر، هنگام ایجاد PeriodicWorkRequest
، یک flexInterval
به همراه repeatInterval
ارسال میکنید. دوره انعطاف پذیری از repeatInterval - flexInterval
شروع می شود و تا پایان فاصله می رود.
در زیر نمونه ای از کارهای دوره ای است که می تواند در 15 دقیقه آخر هر دوره یک ساعته اجرا شود.
کاتلین
val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>( 1, TimeUnit.HOURS, // repeatInterval (the period cycle) 15, TimeUnit.MINUTES) // flexInterval .build()
جاوا
WorkRequest saveRequest = new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS, 15, TimeUnit.MINUTES) .build();
فاصله تکرار باید بزرگتر یا مساوی PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
و بازه انعطاف پذیری باید بزرگتر یا مساوی PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS
باشد.MIN_PERIODIC_FLEX_MILLIS.
اثر محدودیت ها بر کار دوره ای
شما می توانید محدودیت هایی را برای کارهای دوره ای اعمال کنید. به عنوان مثال، میتوانید یک محدودیت به درخواست کاری خود اضافه کنید به طوری که کار فقط زمانی اجرا شود که دستگاه کاربر در حال شارژ شدن است. در این حالت، حتی اگر بازه تکرار تعریف شده بگذرد، PeriodicWorkRequest
تا زمانی که این شرط برآورده نشود اجرا نخواهد شد. این میتواند باعث شود که اجرای خاصی از کار شما به تأخیر بیفتد، یا حتی اگر شرایط در بازه زمانی اجرا برآورده نشود، از بین برود.
محدودیت های کاری
محدودیت ها تضمین می کند که کار تا زمانی که شرایط بهینه برآورده شود به تعویق می افتد. محدودیت های زیر برای WorkManager در دسترس هستند.
نوع شبکه | نوع شبکه مورد نیاز برای اجرای کار شما را محدود می کند. به عنوان مثال، Wi-Fi ( UNMETERED ). |
باتری کم نیست | وقتی روی true تنظیم شود، اگر دستگاه در حالت باتری کم باشد، کار شما اجرا نخواهد شد. |
نیاز به شارژ | وقتی روی true تنظیم شود، کار شما فقط زمانی اجرا می شود که دستگاه در حال شارژ باشد. |
DeviceIdle | هنگامی که روی true تنظیم شود، لازم است دستگاه کاربر قبل از اجرای کار بیکار باشد. این می تواند برای اجرای عملیات دسته ای مفید باشد که در غیر این صورت ممکن است تأثیر منفی بر عملکرد سایر برنامه هایی داشته باشد که به طور فعال در دستگاه کاربر اجرا می شوند. |
StorageNotLow | وقتی روی true تنظیم شود، اگر فضای ذخیره سازی کاربر در دستگاه خیلی کم باشد، کار شما اجرا نمی شود. |
برای ایجاد مجموعه ای از محدودیت ها و مرتبط کردن آن با برخی کارها، یک نمونه Constraints
با استفاده از Contraints.Builder()
ایجاد کنید و آن را به WorkRequest.Builder()
خود اختصاص دهید.
به عنوان مثال، کد زیر یک درخواست کاری ایجاد میکند که تنها زمانی اجرا میشود که دستگاه کاربر هم در حال شارژ و هم در Wi-Fi باشد:
کاتلین
val constraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build() val myWorkRequest: WorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setConstraints(constraints) .build()
جاوا
Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build(); WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setConstraints(constraints) .build();
وقتی چندین محدودیت مشخص شده باشد، کار شما فقط زمانی اجرا می شود که همه محدودیت ها برآورده شوند.
در صورتی که در حین اجرای کار شما محدودیتی برآورده نشود، WorkManager کارگر شما را متوقف خواهد کرد. پس از برآورده شدن تمام محدودیتها، کار دوباره امتحان میشود.
کار با تاخیر
در صورتی که کار شما هیچ محدودیتی نداشته باشد یا هنگامی که کار شما در نوبت قرار می گیرد، تمام محدودیت ها برآورده می شود، سیستم ممکن است تصمیم بگیرد که کار را بلافاصله اجرا کند. اگر نمی خواهید کار بلافاصله اجرا شود، می توانید مشخص کنید که کار شما پس از حداقل تاخیر اولیه شروع شود.
در اینجا نمونه ای از نحوه تنظیم کار خود را به گونه ای تنظیم کنید که حداقل 10 دقیقه پس از قرار گرفتن در صف اجرا شود.
کاتلین
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setInitialDelay(10, TimeUnit.MINUTES) .build()
جاوا
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setInitialDelay(10, TimeUnit.MINUTES) .build();
در حالی که این مثال نحوه تنظیم تاخیر اولیه برای OneTimeWorkRequest
را نشان می دهد، همچنین می توانید یک تاخیر اولیه را برای PeriodicWorkRequest
تنظیم کنید. در این صورت، تنها اجرای اول کار دوره ای شما به تاخیر می افتد.
تلاش مجدد و خط مشی عقب نشینی
اگر می خواهید که WorkManager کار شما را دوباره امتحان کند، می توانید Result.retry()
از worker خود برگردانید. سپس کار شما مطابق با سیاست تاخیر و عقب نشینی مجدد برنامه ریزی می شود.
تأخیر عقبنشینی، حداقل زمان انتظار را قبل از امتحان مجدد کارتان پس از اولین تلاش مشخص میکند. این مقدار نمی تواند کمتر از 10 ثانیه (یا MIN_BACKOFF_MILLIS ) باشد.
خط مشی Backoff تعیین می کند که چگونه تاخیر عقب نشینی باید در طول زمان برای تلاش های مجدد بعدی افزایش یابد. WorkManager از 2 خط مشی عقب نشینی،
LINEAR
وEXPONENTIAL
پشتیبانی می کند.
هر درخواست کاری دارای یک خط مشی عقب نشینی و تاخیر عقب نشینی است. خطمشی پیشفرض EXPONENTIAL
با 30 ثانیه تاخیر است، اما میتوانید این مورد را در پیکربندی درخواست کاری خود لغو کنید.
در اینجا نمونه ای از سفارشی سازی تاخیر و خط مشی عقب نشینی آورده شده است.
کاتلین
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build()
جاوا
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .setBackoffCriteria( BackoffPolicy.LINEAR, OneTimeWorkRequest.MIN_BACKOFF_MILLIS, TimeUnit.MILLISECONDS) .build();
در این مثال، حداقل تاخیر عقبنشینی روی حداقل مقدار مجاز، 10 ثانیه تنظیم شده است. از آنجایی که خطمشی LINEAR
است، با هر تلاش جدید، فاصله تلاش مجدد تقریباً 10 ثانیه افزایش مییابد. برای مثال، اولین اجرای که با Result.retry()
تمام میشود، پس از 10 ثانیه مجدداً انجام میشود، و به دنبال آن 20، 30، 40 و به همین ترتیب، اگر کار به بازگشت Result.retry()
پس از تلاشهای بعدی ادامه دهد. اگر خط مشی عقب نشینی روی EXPONENTIAL
تنظیم می شد، دنباله مدت زمان تلاش مجدد به 20، 40، 80 و غیره نزدیک تر خواهد بود.
کار را تگ کنید
هر درخواست کاری یک شناسه منحصر به فرد دارد که می توان از آن برای شناسایی بعداً آن کار برای لغو کار یا مشاهده پیشرفت آن استفاده کرد.
اگر گروهی از کارهای منطقی مرتبط دارید، ممکن است برچسب گذاری آن موارد کاری نیز برای شما مفید باشد. برچسبگذاری به شما امکان میدهد با گروهی از درخواستهای کاری با هم کار کنید.
به عنوان مثال، WorkManager.cancelAllWorkByTag(String)
تمام درخواستهای کاری با یک برچسب خاص را لغو میکند و WorkManager.getWorkInfosByTag(String)
فهرستی از اشیاء WorkInfo را برمیگرداند که میتوان از آنها برای تعیین وضعیت فعلی استفاده کرد.
کد زیر نشان می دهد که چگونه می توانید یک برچسب "پاکسازی" را به کار خود اضافه کنید:
کاتلین
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>() .addTag("cleanup") .build()
جاوا
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class) .addTag("cleanup") .build();
در نهایت، چندین برچسب را می توان به یک درخواست کاری اضافه کرد. در داخل این تگ ها به عنوان مجموعه ای از رشته ها ذخیره می شوند. برای دریافت مجموعه تگ های مرتبط با WorkRequest
می توانید از WorkInfo.getTags() استفاده کنید.
از کلاس Worker
خود، می توانید مجموعه تگ های آن را از طریق ListenableWorker.getTags() بازیابی کنید.
اختصاص داده های ورودی
کار شما ممکن است برای انجام کار به داده های ورودی نیاز داشته باشد. به عنوان مثال، کاری که آپلود یک تصویر را انجام می دهد ممکن است نیاز به آپلود URI تصویر به عنوان ورودی داشته باشد.
مقادیر ورودی به صورت جفت کلید-مقدار در یک آبجکت Data
ذخیره میشوند و میتوانند بر اساس درخواست کاری تنظیم شوند. WorkManager هنگام اجرای کار، Data
ورودی را به کار شما تحویل می دهد. کلاس Worker
می تواند با فراخوانی Worker.getInputData()
به آرگومان های ورودی دسترسی پیدا کند. کد زیر نشان می دهد که چگونه می توانید یک نمونه Worker
ایجاد کنید که به داده های ورودی نیاز دارد و چگونه آن را در درخواست کاری خود ارسال کنید.
کاتلین
// Define the Worker requiring input class UploadWork(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) { override fun doWork(): Result { val imageUriInput = inputData.getString("IMAGE_URI") ?: return Result.failure() uploadFile(imageUriInput) return Result.success() } ... } // Create a WorkRequest for your Worker and sending it input val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>() .setInputData(workDataOf( "IMAGE_URI" to "http://..." )) .build()
جاوا
// Define the Worker requiring input public class UploadWork extends Worker { public UploadWork(Context appContext, WorkerParameters workerParams) { super(appContext, workerParams); } @NonNull @Override public Result doWork() { String imageUriInput = getInputData().getString("IMAGE_URI"); if(imageUriInput == null) { return Result.failure(); } uploadFile(imageUriInput); return Result.success(); } ... } // Create a WorkRequest for your Worker and sending it input WorkRequest myUploadWork = new OneTimeWorkRequest.Builder(UploadWork.class) .setInputData( new Data.Builder() .putString("IMAGE_URI", "http://...") .build() ) .build();
به طور مشابه، کلاس Data
می تواند برای خروجی یک مقدار بازگشتی استفاده شود. داده های ورودی و خروجی با جزئیات بیشتری در بخش پارامترهای ورودی و مقادیر برگشتی پوشش داده شده است.
مراحل بعدی
در صفحه ایالت ها و مشاهده ، درباره وضعیت های کاری و نحوه نظارت بر پیشرفت کارتان بیشتر خواهید آموخت.