يشكّل هذا الدرس التطبيقي جزءًا من الدورة التدريبية لأساسيات Android Kotlin. ستحصل على أقصى قيمة ممكنة من هذه الدورة التدريبية إذا كنت تستخدم الدروس التطبيقية حول الترميز بشكل متسلسل. يتم إدراج جميع الدروس التطبيقية حول ترميز الدورات التدريبية في الصفحة المقصودة لدروس الترميز Android Kotlin Fundamentals.
مقدمة
تحتاج معظم التطبيقات الحقيقية إلى تنفيذ مهام طويلة الأمد في الخلفية. على سبيل المثال، قد يحمّل التطبيق ملفات إلى خادم أو يزامن البيانات من خادم ويحفظها في قاعدة بيانات Room
أو يرسل سجلات إلى خادم أو ينفذ عمليات باهظة التكلفة على البيانات. يجب إجراء هذه العمليات في الخلفية، خارج سلسلة محادثات واجهة المستخدم (سلسلة المحادثات الرئيسية). تستهلك المهام في الخلفية موارد محدودة للجهاز، مثل ذاكرة الوصول العشوائي والبطارية. وقد يؤدي ذلك إلى تجربة سيئة للمستخدم إذا لم تتم معالجته بشكل صحيح.
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استخدام WorkManager
لجدولة مهمة في الخلفية بطريقة فعّالة وفعّالة. لمعرفة المزيد من المعلومات عن الحلول الأخرى المتوفّرة للمعالجة في الخلفية في نظام التشغيل Android، راجِع دليل المعالجة الخلفية.
ما يجب معرفته
- كيفية استخدام
ViewModel
وLiveData
ومكوّنات AndroidRoom
. - كيفية إجراء تغييرات على صف
LiveData
. - كيفية إنشاء كوروتين وإطلاقه
- كيفية استخدام محوّلات الربط في ربط البيانات.
- كيفية تحميل بيانات ذاكرة التخزين المؤقت باستخدام نمط مستودع.
ما ستتعرَّف عليه
- كيفية إنشاء
Worker
تمثّل وحدة عمل - كيفية إنشاء
WorkRequest
لطلب تنفيذ العمل. - كيفية إضافة القيود إلى
WorkRequest
لتحديد كيفية ووقت تشغيل عامل - طريقة استخدام
WorkManager
لجدولة المهام في الخلفية.
الإجراءات التي ستنفذّها
- يمكنك إنشاء مشغّل لتنفيذ مهمة في الخلفية من أجل جلب قائمة تشغيل الفيديو DevBytes من الشبكة مسبقًا.
- جدوِل تشغيل العمّال بشكل دوري.
- يمكنك إضافة قيود على
WorkRequest
. - يمكنك جدولة
WorkRequest
دورية يتم تنفيذها مرة واحدة في اليوم.
في هذا الدرس التطبيقي حول الترميز، تعمل على تطبيق DevBytes الذي طوّرته في درس تطبيقي سابق حول الترميز. (إذا لم يكن لديك هذا التطبيق، يمكنك تنزيل رمز بدء الدرس.)
يعرض تطبيق DevBytes قائمة فيديوهات DevByte، وهي فيديوهات تعليمية قصيرة أنشأها فريق علاقات مطوّري برامج Google لنظام التشغيل Android. تقدم الفيديوهات ميزات مطوّري البرامج وأفضل الممارسات لتطوير Android.
يمكنك تحسين تجربة المستخدم في التطبيق من خلال جلب الفيديوهات مسبقًا مرة واحدة في اليوم. ويضمن ذلك حصول المستخدم على محتوى جديد فور فتح التطبيق.
في هذه المهمة، يمكنك تنزيل رمز البدء وفحصه.
الخطوة 1: تنزيل تطبيق بدء التشغيل وتشغيله
يمكنك مواصلة العمل من خلال تطبيق DevBytes الذي أنشأته في الدرس التطبيقي السابق (في حال توفّره). ويمكنك بدلاً من ذلك تنزيل تطبيق إجراء التفعيل.
في هذه المَهمة، نزِّل تطبيق إجراء التفعيل وتحقَّق من رمز إجراء التفعيل.
- إذا لم يكن لديك تطبيق DevBytes من قبل، نزِّل رمز DevBytes للمبتدئين في هذا الدرس التطبيقي من DevBytesRepository من GitHub.
- فكّ ضغط الرمز وافتح المشروع في Android Studio.
- أصلح جهازك الاختباري أو المحاكي بالإنترنت إذا لم يكن متصلاً من قبل. إنشاء التطبيق وتشغيله، يجلب التطبيق قائمة فيديوهات DevByte من الشبكة ويعرضها.
- في التطبيق، انقر على أي فيديو لفتحه في تطبيق YouTube.
الخطوة 2: استكشاف الرمز
يتضمّن تطبيق المبتدئين الكثير من الرموز التي تمّ تقديمها في الدرس التطبيقي السابق حول الترميز. يتضمّن رمز بدء الدرس التطبيقي هذا الرمز وتم تخصيص واجهة مستخدم وذاكرة تخزين مؤقت بلا اتصال بالإنترنت ووحدات تخزين. يمكنك التركيز على جدولة مهمة الخلفية باستخدام WorkManager
.
- في "استوديو Android"، وسِّع كل الحِزم.
- استكشِف حزمة
database
. تحتوي الحزمة على كيانات قاعدة البيانات وقاعدة البيانات المحلية التي يتم تنفيذها باستخدامRoom
. - استكشِف حزمة
repository
. تحتوي الحزمة على فئةVideosRepository
التي تستخرج طبقة البيانات من بقية التطبيق. - اكتشف بقية رموز إجراء التفعيل بنفسك وبمساعدة الدرس التطبيقي السابق.
WorkManager
هي أحد مكوّنات Android الأساسية وجزء من Android Jetpack. WorkManager
مخصّص للعمل في الخلفية الذي يمكن تأجيله ويتطلب التنفيذ المضمون:
- مؤجلة تعني أن العمل غير مطلوب للتشغيل على الفور. على سبيل المثال، من الممكن تأجيل إرسال البيانات التحليلية إلى الخادم أو مزامنة قاعدة البيانات في الخلفية.
- التنفيذ المضمون يعني أنه سيتم تنفيذ المهمة حتى في حال إغلاق التطبيق أو إعادة تشغيل الجهاز.
وعلى الرغم من أنّ نظام WorkManager
يُشغِّل العمل في الخلفية، فإنه يتولى مشاكل التوافق وأفضل الممارسات لسلامة البطارية والنظام. يوفر WorkManager
التوافق مع المستوى 14 لواجهة برمجة التطبيقات. سيختار WorkManager
طريقة مناسبة لجدولة مهمة في الخلفية، بناءً على مستوى واجهة برمجة تطبيقات الجهاز. وقد يستخدم الإصدار JobScheduler
(على الإصدار 23 والإصدارات الأحدث من واجهة برمجة التطبيقات) أو مزيجًا من AlarmManager
وBroadcastReceiver
.
ويتيح لك WorkManager
أيضًا وضع معايير حول وقت تنفيذ المهمة في الخلفية. على سبيل المثال، قد ترغب في تشغيل المهمة فقط عند استيفاء حالة البطارية أو حالة الشبكة أو حالة الشحن لمعايير محددة. ستتعلّم لاحقًا كيفية فرض قيود لاحقًا في هذا الدرس التطبيقي حول الترميز.
في هذا الدرس التطبيقي حول الترميز، يمكنك جدولة مهمة للحصول مسبقًا على قائمة تشغيل الفيديو DevBytes من الشبكة مرة واحدة في اليوم. لجدولة هذه المهمة، يمكنك استخدام مكتبة WorkManager
.
- افتح ملف
build.gradle (Module:app)
وأضِف اعتماديةWorkManager
إلى المشروع.
إذا كنت تستخدم أحدث إصدار من المكتبة، يجب أن يجمع تطبيق الحل كما هو متوقع. وإذا لم يحدث ذلك، جرِّب حل المشكلة، أو يمكنك الرجوع إلى إصدار المكتبة الموضَّح أدناه.
// WorkManager dependency
def work_version = "1.0.1"
implementation "android.arch.work:work-runtime-ktx:$work_version"
- عليك مزامنة مشروعك والتأكُّد من عدم حدوث أخطاء في التجميع.
قبل إضافة الرمز إلى المشروع، اطّلِع على الصفوف التالية في مكتبة WorkManager
:
Worker
هذا الصف هو المكان الذي تحدِّد فيه العمل الفعلي (المهمة) الذي سيتم تشغيله في الخلفية. يمكنك تمديد هذه الفئة وإلغاء طريقةdoWork()
. والطريقةdoWork()
هي المكان الذي يمكنك من خلاله وضع رمز لتنفيذه في الخلفية، مثل مزامنة البيانات مع الخادم أو معالجة الصور. لقد نفّذتWorker
في هذه المهمة.WorkRequest
يمثّل هذا الصف طلبًا لتشغيل العاملين في الخلفية. استخدِمWorkRequest
لضبط كيفية تشغيل مهمة المشغِّل ووقتها، وذلك بمساعدةConstraints
، مثل توصيل الجهاز أو اتصاله بشبكة Wi-Fi. لقد نفّذتWorkRequest
في مهمة لاحقة.WorkManager
يعمل هذا الصف على تحديد موعدWorkRequest
وتشغيله.WorkManager
هو جدول زمني لطلبات العمل بطريقة تنشر الحِمل على موارد النظام مع الالتزام بالقيود التي تحدّدها. لقد نفّذتWorkManager
في مهمة لاحقة.
الخطوة 1: إنشاء مشغّل
في هذه المهمة، يمكنك إضافة Worker
لجلب قائمة تشغيل الفيديو DevBytes مسبقًا في الخلفية.
- داخل حزمة
devbyteviewer
، أنشِئ حزمة جديدة باسمwork
. - داخل الحزمة
work
، أنشئ فئة Kotlin جديدة باسمRefreshDataWorker
. - تمديد الصف الدراسي
RefreshDataWorker
من الصفCoroutineWorker
. أدخِلcontext
وWorkerParameters
كمعلّمات وضع.
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
}
- لحل خطأ الفئة المجرّدة، يمكنك إلغاء طريقة
doWork()
داخل الصفRefreshDataWorker
.
override suspend fun doWork(): Result {
return Result.success()
}
دالة التعليق هي وظيفة يمكن إيقافها مؤقتًا واستئنافها لاحقًا. يمكن أن تنفّذ وظيفة التعليق عملية تشغيل طويلة وتنتظر اكتمال العملية بدون حظر سلسلة المحادثات الرئيسية.
الخطوة 2: تنفيذ DoWork()
يتم استدعاء طريقة doWork()
داخل الفئة Worker
في سلسلة محادثات في الخلفية. تعمل الطريقة بشكل متزامن، ومن المفترض أن تعرض كائن ListenableWorker.Result
. يمنح نظام Android Worker
مدة 10 دقائق كحد أقصى لإكمال تنفيذه وعرض كائن ListenableWorker.Result
. بعد انتهاء هذه الفترة، سيوقف النظام فرض Worker
.
لإنشاء عنصر ListenableWorker.Result
، يمكنك استدعاء إحدى الطرق الثابتة التالية للإشارة إلى حالة اكتمال العمل في الخلفية:
Result.success()
: اكتمل العمل بنجاح.Result.failure()
: اكتمال العمل مع تعذُّر نهائي.Result.retry()
: حدث خطأ عابر في العمل ويجب إعادة المحاولة.
في هذه المَهمّة، يمكنك استخدام طريقة doWork()
لجلب قائمة تشغيل الفيديو من شبكة DevBytes من الشبكة. يمكنك إعادة استخدام الطرق الحالية في الفئة VideosRepository
لاسترداد البيانات من الشبكة.
- في الصف
RefreshDataWorker
، داخلdoWork()
، يمكنك إنشاء عنصرVideosDatabase
وكائنVideosRepository
.
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
return Result.success()
}
- في الصف
RefreshDataWorker
، داخلdoWork()
، فوق عبارةreturn
، عليك استدعاء الطريقةrefreshVideos()
في الكتلةtry
. إضافة سجل لتتبع وقت تشغيل العامل.
try {
repository.refreshVideos( )
Timber.d("Work request for sync is run")
} catch (e: HttpException) {
return Result.retry()
}
لحل الخطأ "&&;;لم يتم حلها" كمرجع &&;;; استيراد retrofit2.HttpException
".
- في ما يلي الصف
RefreshDataWorker
الكامل كمرجع لك:
class RefreshDataWorker(appContext: Context, params: WorkerParameters) :
CoroutineWorker(appContext, params) {
override suspend fun doWork(): Result {
val database = getDatabase(applicationContext)
val repository = VideosRepository(database)
try {
repository.refreshVideos()
} catch (e: HttpException) {
return Result.retry()
}
return Result.success()
}
}
يحدّد Worker
وحدة عمل، ويحدّد WorkRequest
كيفية تنفيذ العمل ووقته. هناك تطبيقان ملموسان للصف WorkRequest
:
- الصف
OneTimeWorkRequest
مخصّص للمهام الفردية. (تحدث مهمة مرة واحدة مرة واحدة فقط.) - إنّ صف
PeriodicWorkRequest
مخصّص للعمل بشكل دوري، وهو متكرّر على فترات زمنية.
يمكن أن تكون المهام فردية أو دورية، لذلك اختر الصف وفقًا لذلك. لمزيد من المعلومات حول جدولة عمل متكرّر، يُرجى الاطّلاع على مستندات العمل المتكرّرة.
في هذه المهمة، يمكنك تحديد WorkRequest
وجدولتها لتشغيل عامل التشغيل الذي أنشأته في المهمة السابقة.
الخطوة 1: إعداد عمل متكرّر
ضمن تطبيق Android، تكون الفئة Application
هي الفئة الأساسية التي تحتوي على جميع المكونات الأخرى، مثل الأنشطة والخدمات. عند إنشاء عملية التطبيق أو الحزمة، يتم إنشاء مثيل للفئة Application
(أو أي فئة فرعية من Application
) قبل أي فئة أخرى.
في هذا النموذج للتطبيق، الفئة DevByteApplication
هي فئة فرعية من الصف Application
. يمثّل الصف DevByteApplication
مكانًا مناسبًا لتحديد موعد WorkManager
.
- في الصف
DevByteApplication
، أنشِئ طريقة تُسمىsetupRecurringWork()
لإعداد العمل في الخلفية المتكرّر.
/**
* Setup WorkManager background job to 'fetch' new network data daily.
*/
private fun setupRecurringWork() {
}
- داخل طريقة
setupRecurringWork()
، يمكنك إنشاء طلب عمل دوري وإعداده مرة واحدة في اليوم، باستخدام طريقةPeriodicWorkRequestBuilder()
. سجّل في صفRefreshDataWorker
الذي أنشأته في المهمة السابقة. تمرّر فاصلاً متكررًا مدته1
مع وحدة زمنية منTimeUnit.
DAYS
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.build()
لإصلاح الخطأ، استورِد java.util.concurrent.TimeUnit
.
الخطوة 2: جدولة WorkRequest مع WorkManager
بعد تعريف WorkRequest
، يمكنك جدولته مع WorkManager
، باستخدام طريقة enqueueUniquePeriodicWork()
. تسمح لك هذه الطريقة بإضافة PeriodicWorkRequest
يحمل اسمًا فريدًا إلى قائمة الانتظار، حيث لا يمكن تفعيل أكثر من PeriodicWorkRequest
واحد من الاسم نفسه في كل مرة.
على سبيل المثال، قد ترغب في تنشيط عملية مزامنة واحدة فقط. إذا كانت هناك عملية مزامنة واحدة في انتظار المراجعة، يمكنك اختيار السماح بتشغيلها أو استبدالها بأعمالك الجديدة، وذلك باستخدام CurrentPeriodicWorkPolicy.
لمزيد من المعلومات حول طرق تحديد موعد WorkRequest
، يُرجى الاطّلاع على مستندات WorkManager
.
- في الصف
RefreshDataWorker
، أضِف كائنًا مصاحبًا في بداية الصف. حدِّد اسم عمل لتحديد هذا العامل بشكلٍ فريد.
companion object {
const val WORK_NAME = "com.example.android.devbyteviewer.work.RefreshDataWorker"
}
- في الصف
DevByteApplication
، في نهاية طريقةsetupRecurringWork()
، يمكنك جدولة العمل باستخدام الطريقةenqueueUniquePeriodicWork()
. أدخِل تعدادKEEP
لـ CurrentPeriodicWorkPolicy. أدخِلrepeatingRequest
كمَعلمةPeriodicWorkRequest
.
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
في حال توفر عمل في انتظار المراجعة (غير مكتمل) بالاسم نفسه، ستعمل المعلمة ExistingPeriodicWorkPolicy.
KEEP
على إبقاء العمل الدائري السابق WorkManager
وتجاهل طلب العمل الجديد.
- في بداية الصف
DevByteApplication
، أنشئ كائنCoroutineScope
. أدخِلDispatchers.Default
كمعلَمة طريقة الإنشاء.
private val applicationScope = CoroutineScope(Dispatchers.Default)
- في الصف
DevByteApplication
، أضِف طريقة جديدة تُسمّىdelayedInit()
لبدء كوروتين.
private fun delayedInit() {
applicationScope.launch {
}
}
- اتّبِع الرقم
setupRecurringWork()
داخل طريقةdelayedInit()
. - حرِّك إعداد الأخشاب من طريقة
onCreate()
إلى طريقةdelayedInit()
.
private fun delayedInit() {
applicationScope.launch {
Timber.plant(Timber.DebugTree())
setupRecurringWork()
}
}
- في الصف
DevByteApplication
، في نهاية طريقةonCreate()
، أضف استدعاءً للطريقةdelayedInit()
.
override fun onCreate() {
super.onCreate()
delayedInit()
}
- افتح الجزء Logcat في أسفل نافذة Android Studio. الفلترة على
RefreshDataWorker
- شغِّل التطبيق. وحدِّد التطبيق
WorkManager
جدول الأعمال المتكررة على الفور.
في جزء Logcat، لاحِظ بيانات السجلّ التي تشير إلى جدولة طلب العمل، ثم يتم تشغيلها بنجاح.
D/RefreshDataWorker: Work request for sync is run I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
يتم عرض سجل WM-WorkerWrapper
من مكتبة WorkManager
، لذلك لا يمكنك تغيير رسالة السجل هذه.
الخطوة 3: (اختياري) جدولة أداة WorkRequest للحصول على الحد الأدنى من الفاصل الزمني
في هذه الخطوة، عليك تقليل الفاصل الزمني من يوم واحد إلى 15 دقيقة. ويمكنك إجراء ذلك حتى تتمكن من الاطلاع على السجلات لطلب عمل دوري.
- في الصف
DevByteApplication
، ضمن طريقةsetupRecurringWork()
، علِّق تعريفrepeatingRequest
الحالي. أضِف طلب عمل جديدًا بفاصل زمني متكرر متكرر مدته15
دقيقة.
// val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
// .build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.build()
- افتح لوحة Logcat في "استوديو Android" وفلترًا في
RefreshDataWorker
. لمحو السجلات السابقة، انقر على رمز محو السجلّات.
- شغِّل التطبيق وسيحدِّد تطبيق
WorkManager
عملك المتكرّر على الفور. في لوحة Logcat، لاحظ السجلات: يتم تشغيل طلب العمل مرة واحدة كل 15 دقيقة. انتظِر 15 دقيقة للاطِّلاع على مجموعة أخرى من سجلّات طلبات العمل. يمكنك ترك التطبيق قيد التشغيل أو إغلاقه، علمًا بأنّه يجب أن يعمل مدير العمل.
يُرجى العِلم أنّ الفاصل الزمني يكون في بعض الأحيان أقل من 15 دقيقة، وأحيانًا أكثر من 15 دقيقة. (يخضع التوقيت الدقيق لعمليات تحسين بطارية نظام التشغيل.)
12:44:40 D/RefreshDataWorker: Work request for sync is run 12:44:40 I/WM-WorkerWrapper: Worker result SUCCESS for Work 12:59:24 D/RefreshDataWorker: Work request for sync is run 12:59:24 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:15:03 D/RefreshDataWorker: Work request for sync is run 13:15:03 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:29:22 D/RefreshDataWorker: Work request for sync is run 13:29:22 I/WM-WorkerWrapper: Worker result SUCCESS for Work 13:44:26 D/RefreshDataWorker: Work request for sync is run 13:44:26 I/WM-WorkerWrapper: Worker result SUCCESS for Work
تهانينا. لقد أنشأت عاملاً وحددت موعدًا لطلب العمل مع WorkManager
. ولكن هناك مشكلة: لم تحدد أي قيود. سيجدوِن WorkManager
العمل مرة واحدة في اليوم، حتى إذا كان شحن البطارية منخفضًا أو عندما يكون في وضع السكون أو لا يتوفّر اتصال بالشبكة. وسيؤثّر ذلك في أداء بطارية الجهاز وأدائه، وقد يؤدي إلى ترك انطباع سيئ لدى المستخدم.
في المهمة التالية، يمكنك معالجة هذه المشكلة عن طريق إضافة قيود.
في المهمة السابقة، استخدمت WorkManager
لجدولة طلب عمل. في هذه المهمة، يمكنك إضافة معايير لوقت تنفيذ العمل.
عند تحديد WorkRequest
، يمكنك وضع قيود على الحالات التي يجب فيها تشغيل Worker
. على سبيل المثال، قد تريد تحديد عدم تشغيل العمل إلا عندما يكون الجهاز غير نشِط لفترة قصيرة، أو فقط عندما يكون الجهاز متصلاً بشبكة Wi-Fi. ويمكنك أيضًا تحديد سياسة التراجع عن إعادة محاولة العمل. القيود المتوافقة هي الطرق المحدَّدة في Constraints.Builder
. لمعرفة مزيد من المعلومات، يُرجى الاطِّلاع على تحديد طلبات العمل.
الخطوة 1: إضافة كائن قيود ووضع قيود واحدة
في هذه الخطوة، يمكنك إنشاء عنصر Constraints
وضبط قيد واحد على الكائن، وهو قيد من نوع الشبكة. (ليس من السهل ملاحظة السجلات بقيود واحدة فقط. في خطوة لاحقة، يمكنك إضافة قيود أخرى.)
- في الصف
DevByteApplication
، في بدايةsetupRecurringWork()
، حدِّدval
من النوعConstraints
. استخدِم الطريقةConstraints.Builder()
.
val constraints = Constraints.Builder()
لإصلاح الخطأ، استورِد androidx.work.Constraints
.
- استخدِم الطريقة
setRequiredNetworkType()
لإضافة قيد من نوع الشبكة إلى العنصرconstraints
. يمكنك استخدام تعدادUNMETERED
بحيث لا يتم تشغيل طلب العمل إلا عندما يكون الجهاز متصلاً بشبكة غير تفرض تكلفة استخدام.
.setRequiredNetworkType(NetworkType.UNMETERED)
- استخدام الطريقة
build()
لإنشاء القيود من أداة الإنشاء.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
عليك الآن ضبط الكائن Constraints
الذي تم إنشاؤه حديثًا على طلب العمل.
- في الصف
DevByteApplication
، داخل طريقةsetupRecurringWork()
، اضبط الكائنConstraints
على طلب العمل الدوريrepeatingRequest
. لضبط القيود، أضِف طريقةsetConstraints()
أعلى استدعاء طريقةbuild()
.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(15, TimeUnit.MINUTES)
.setConstraints(constraints)
.build()
الخطوة 2: تشغيل التطبيق وملاحظة السجلات
في هذه الخطوة، يمكنك تشغيل التطبيق وملاحظة تنفيذ طلب العمل المحدود في الخلفية على فترات زمنية.
- ألغِ تثبيت التطبيق من الجهاز أو المحاكي لإلغاء أي مهام مجدولة مسبقًا.
- افتح لوحة Logcat في "استوديو Android". في جزء Logcat (محو سجلّات)، عليك محو السجلّات السابقة بالنقر على رمز محو سجلّات السجلّ (
) على يمين الصفحة. الفلترة على
work
- أوقِف شبكة Wi-Fi في الجهاز أو المحاكي حتى تتمكّن من معرفة آلية عمل القيود. ويحدّد الرمز الحالي قيدًا واحدًا فقط، ما يشير إلى ضرورة تشغيل الطلب على شبكة غير تفرض تكلفة استخدام. نظرًا لأن شبكة Wi-Fi متوقفة، فإن الجهاز ليس متصلاً بالشبكة أو فيه قياس أو قياسه. وبالتالي، لن يتم الوفاء بهذه القيود.
- شغِّل التطبيق ولاحظ لوحة Logcat (لوحة السجل). تُحدِّد الخاصية
WorkManager
مهمة الخلفية على الفور. وبسبب عدم استيفاء قيد الشبكة، لن يتم تنفيذ المهمة.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled
- شغِّل شبكة Wi-Fi في الجهاز أو المحاكي وشاهد لوحة Logcat. يتم الآن تشغيل مهمة الخلفية المجدولة كل 15 دقيقة تقريبًا، طالما تم استيفاء قيد الشبكة.
11:31:44 D/DevByteApplication: Periodic Work request for sync is scheduled 11:31:47 D/RefreshDataWorker: Work request for sync is run 11:31:47 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 11:46:45 D/RefreshDataWorker: Work request for sync is run 11:46:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:03:05 D/RefreshDataWorker: Work request for sync is run 12:03:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:16:45 D/RefreshDataWorker: Work request for sync is run 12:16:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:31:45 D/RefreshDataWorker: Work request for sync is run 12:31:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 12:47:05 D/RefreshDataWorker: Work request for sync is run 12:47:05 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...] 13:01:45 D/RefreshDataWorker: Work request for sync is run 13:01:45 I/WM-WorkerWrapper: Worker result SUCCESS for Work [...]
الخطوة 3: إضافة المزيد من القيود
في هذه الخطوة، يمكنك إضافة القيود التالية إلى PeriodicWorkRequest
:
- مستوى شحن البطارية منخفض.
- جارٍ شحن الجهاز.
- الجهاز غير نشِط لفترة قصيرة، ولا يتوفّر إلا في مستوى واجهة برمجة التطبيقات 23 (Android M) والإصدارات الأحدث.
نفِّذ ما يلي في صف DevByteApplication
.
- في الصف
DevByteApplication
، وضمن طريقةsetupRecurringWork()
، أشِر إلى أن طلب العمل يجب أن يعمل فقط إذا لم تكن طاقة البطارية منخفضة. أضِف القيود قبل استدعاء طريقةbuild()
، واستخدِم الطريقةsetRequiresBatteryNotLow()
.
.setRequiresBatteryNotLow(true)
- يمكنك تعديل طلب العمل ليتم تشغيله فقط عندما يكون الجهاز قيد الشحن. أضِف القيود قبل استدعاء طريقة
build()
، واستخدِم الطريقةsetRequiresCharging()
.
.setRequiresCharging(true)
- يمكنك تعديل طلب العمل ليتم تشغيله فقط عندما يكون الجهاز في وضع عدم النشاط. أضِف القيود قبل استدعاء طريقة
build()
، واستخدِم الطريقةsetRequiresDeviceIdle()
. يشغِّل هذا القيد طلب العمل فقط عندما لا يستخدم المستخدم الجهاز بشكل نشط. لا تتوفر هذه الميزة إلا على الإصدار Android 6.0 (Marshmallow) والإصدارات الأحدث، لذا أضِف شرطًا لإصدار SDKM
والإصدارات الأحدث.
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
في ما يلي التعريف الكامل للكائن constraints
.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
- داخل طريقة
setupRecurringWork()
، غيِّر الفاصل الزمني للطلب مرة واحدة في اليوم.
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
في ما يلي التنفيذ الكامل لطريقة setupRecurringWork()
، باستخدام سجلّ يمكنك تتبّعه عند جدولة طلب العمل الدوري.
private fun setupRecurringWork() {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.apply {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setRequiresDeviceIdle(true)
}
}
.build()
val repeatingRequest = PeriodicWorkRequestBuilder<RefreshDataWorker>(1, TimeUnit.DAYS)
.setConstraints(constraints)
.build()
Timber.d("Periodic Work request for sync is scheduled")
WorkManager.getInstance().enqueueUniquePeriodicWork(
RefreshDataWorker.WORK_NAME,
ExistingPeriodicWorkPolicy.KEEP,
repeatingRequest)
}
- لإزالة طلب العمل المُجدوَل سابقًا، يجب إلغاء تثبيت تطبيق DevBytes من جهازك أو من أداة المحاكاة.
- شغِّل التطبيق وسيجدون
WorkManager
على الفور طلب العمل. يتم تشغيل طلب العمل مرة واحدة في اليوم، عند استيفاء جميع القيود. - سيتم تشغيل طلب العمل هذا في الخلفية طالما كان التطبيق مثبتًا، حتى في حال عدم تشغيل التطبيق. ولهذا السبب، يجب إلغاء تثبيت التطبيق من الهاتف.
إجابتك صحيحة. لقد نفّذت طلبًا للعمل ملائمًا للبطارية وتم تحديد موعد استرجاع البيانات يوميًا في تطبيق DevBytes، وسيتولى WorkManager
تحديد موعد لتنفيذ العمل وتشغيله، ما يؤدي إلى تحسين موارد النظام. سيشعر المستخدمون وبطارياتهم بالرضا التام.
مشروع "استوديو Android": DevBytesWorkManager
- تسهِّل واجهة برمجة تطبيقات
WorkManager
جدولة المهام المؤجلة وغير المتزامنة التي يجب تشغيلها بشكلٍ موثوق. - تحتاج معظم التطبيقات الحقيقية إلى تنفيذ مهام طويلة الأمد في الخلفية. لجدولة مهمة في الخلفية بطريقة فعّالة وفعالة، استخدِم
WorkManager
. - الصفوف الرئيسية في مكتبة
WorkManager
هيWorker
وWorkRequest
وWorkManager
. - يمثل الصف
Worker
وحدة عمل. لتنفيذ مهمة الخلفية، وسِّع الفئةWorker
وتجاوز طريقةdoWork()
. - تمثّل الفئة
WorkRequest
طلبًا لتنفيذ وحدة عمل.WorkRequest
هي الفئة الأساسية لتحديد معلّمات العمل الذي جدولته فيWorkManager
. - هناك تطبيقان ملموسان للصف
WorkRequest
:OneTimeWorkRequest
للمهام الفردية، وPeriodicWorkRequest
لطلبات العمل الدورية. - عند تحديد
WorkRequest
، يمكنك تحديدConstraints
للإشارة إلى وقت تشغيلWorker
. تشمل القيود عناصر مثل ما إذا كان الجهاز متصلاً، أو ما إذا كان الجهاز غير نشِط لفترة قصيرة، أو ما إذا كان اتصال Wi-Fi متصلاً. - لإضافة قيود على
WorkRequest
، استخدِم الطرق المحدَّدة في مستنداتConstraints.Builder
. مثلاً، للإشارة إلى ضرورة عدم تشغيلWorkRequest
إذا كانت بطارية الجهاز منخفضة، استخدِم الطريقةsetRequiresBatteryNotLow()
المحدَّدة. - بعد تحديد
WorkRequest
، عليك تسليم المهمة إلى نظام Android. ولإجراء ذلك، يمكنك جدولة المهمة باستخدام إحدى طرقenqueue
WorkManager
. - يعتمد الوقت الدقيق لتنفيذ
Worker
على القيود المستخدمة فيWorkRequest
وعلى تحسينات النظام. تم تصميمWorkManager
لتقديم أفضل سلوك ممكن في ظل هذه القيود.
دورة Udacity:
مستندات مطوّر برامج Android:
غير ذلك:
يسرد هذا القسم المهام الدراسية المحتملة للطلاب الذين يعملون من خلال هذا الدرس التطبيقي حول الترميز في إطار دورة تدريبية يُديرها معلِّم. يجب أن ينفِّذ المعلّم ما يلي:
- يمكنك تخصيص واجب منزلي إذا لزم الأمر.
- التواصل مع الطلاب بشأن كيفية إرسال الواجبات المنزلية
- وضع درجات للواجبات المنزلية.
ويمكن للمعلّمين استخدام هذه الاقتراحات بقدر ما يريدون أو بقدر ما يريدون، ويجب عدم التردد في تخصيص أي واجبات منزلية أخرى مناسبة.
إذا كنت تستخدم هذا الدرس التطبيقي بنفسك، يمكنك استخدام هذه الواجبات المنزلية لاختبار معلوماتك.
السؤال 1
ما هي عمليات التنفيذ الملموسة للصف WorkRequest
؟
▢ OneTimeWorkPeriodicRequest
▢ OneTimeWorkRequest
وPeriodicWorkRequest
▢ OneTimeWorkRequest
وRecurringWorkRequest
▢ OneTimeOffWorkRequest
وRecurringWorkRequest
السؤال 2
أي من الصفوف التالية يستخدمها WorkManager
لجدولة مهمة الخلفية على واجهة برمجة التطبيقات 23 والإصدارات الأحدث؟
▢ فقط JobScheduler
▢ BroadcastReceiver
وAlarmManager
▢ AlarmManager
وJobScheduler
▢ Scheduler
وBroadcastReceiver
السؤال 3
ما هي واجهة برمجة التطبيقات التي تستخدمها لإضافة قيود إلى WorkRequest
؟
▢ setConstraints()
▢ addConstraints()
▢ setConstraint()
▢ addConstraintsToWorkRequest()
انتقل إلى الدرس التالي:
وللحصول على روابط إلى دروس تطبيقية أخرى حول الترميز في هذه الدورة التدريبية، يُرجى الاطّلاع على الصفحة المقصودة لتطبيق الدروس التطبيقية حول الترميز Kotlin Fundamentals.