استخدام الـ WorkManager من حزمة JetPack
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته
في الدروس السابقة رأينا طرق كثيرة لجدولة الاعمال والمهام منها الـ Alarm Manager و الـ Android JobScheduler والـ Firebase JobDispatcher. في هذا الدرس سنتعرف على احدث الطرق وافضلها وهو الـ Work Manager.
بماذا يمتاز عن البقية
- يستطيع انشاء خيط حاسوبي لمهامك, لذلك لاداعي لإستخدام احد انماط التصميم.
- ربما يقوم بإستخدام كلاً من الـ Android JobScheduler او Firebase JobDispatcher او AlarmManager اذا دعى الامر لذلك.
- يريحك من قيامك بكتابة الـ Logic للحصول على مواصفات هاتف مستخدم تطبيقك. حتى ترى ايهم المناسب له JobScheduler (تم دعمه من API 21 واحدث) او JobDispatcher (تم دعمه من API 14 واحدث, و يتطلب وجود Google Play Services مثبت في هاتف المستخدم). اي لاداعي للخيره بعد الان فقط قم بإستخدام الـ Work Manager.
- يستطيع عمل Chaining لإعمالك, اي تستطيع ترتيب الاعمال ايهم يبدء اولاً وثانياً وثالثاً.
يعتبر الـ WorkManager احدث شئ في نظام الاندرويد لجدولة المهام والاعمال وتشغيلها في الخلفيه, فهو يحتل جزء مرموق في الـ Android Architecture Components التي اتت مع حزمة الـ JetPack. فهو يستطيع استخدام اي من الـ AlarmManager والـ Firebase JobDispatcher و الـ JobScheduler بدون التدخل منك (فقط سلم عملك الى الـ WorkManager ودع الباقي له في اختيار افضل شئ يراه مناسباً).
رابط اعتماديات المكتبة
خطوات انشاء الـ WorkManager
- بما انه مكتبه خارجية سنحتاج الى اضافة الـ Dependencies له في ملف الـ Gradle.
- ننشئ كلاس جديدة تعمل extends للـ Worker.
- نقوم بعمل Constructor بداخلها يإخد Context و معلومات العمل WorkerParameters.
- نقوم بعمل Override للدالة doWork وبها نضع شفرتنا البرمجية المراد تشغيلها.
الخطوات:
اضافة الـ Dependencies له في ملف الـ Gradle:
// Work Manager
def work_version = "1.0.0-beta05"
implementation "android.arch.work:work-runtime:$work_version"
انشاء كلاس الـ Work:
public class MyJobManager extends Worker {}
عمل Constructor بداخلها يإخد Context و معلومات العمل WorkerParameters:
public class MyJobManager extends Worker {
public MyJobManager(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
...
..
عمل Override للدالة doWork وبها نضع شفرتنا البرمجية المراد تشغيلها:
public class MyJobManager extends Worker {
public MyJobManager(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
// Our Code goes here
// Our Code goes here
// Our Code goes here
return Result.success();
}
}
لاحظ التالي:
- في دالة الـ doWork نقوم بوضع شفرتنا البرمجة المراد تشغيلها.
- نقوم بعمل return للقيم التالية:
- Result.success: في حالة نجاح واتمام الشفرة البرمجية لعملنا.
- Result.retry: في الفشل وهنا نطلب من نظام الاندرويد ان يقوم بإعادة المحاولة.
- Result.failure: في الفشل وهنا نطلب من نظام الاندرويد ان لايقوم بإعادة المحاولة.
ماذا لو اردنا ارسال البيانات من الـ Activity او اي مكون اخر الى هذه الكلاس لإستخدامهم هنا؟
في هذه الحاله نقوم بإستخدام الدالة getInputData للحصول على المعلومات المرسلة, واذا قمنا بمعالجتهم نستطيع ارسالهم الى المكون من خلال وضعهم بداخل عنصر Data وارفاقه في الدالة Result.success كمعطى. للمزيد من التفصيل اطلع على الخطوة التالية:
استقبال البيانات في كلاس الـ Work:
public class MyJobManager extends Worker {
public MyJobManager(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
String name = getInputData().getString("NAME_KEY");
int age = getInputData().getInt("AGE_KEY", -1);
String result = name + age;
Data output = new Data.Builder()
.putString("RESULT_KEY", result)
.build();
return Result.success(output);
}
}
لاحظ التالي:
- قمنا بإستقبال عنصرين بإستخدام الدالة getInputData وهما: اسم بنوع String وعمر بنوع int.
- قمنا بإجراء العملية المراده ووضعنا النتيجه في عنصر String بإسم result.
- قمنا بإنشاء عنصر من نوع Data ووضع النتيجه في داخله.
- قمنا بإرسال النتيجه الى المكون الذي قام بتشغيل هذه الكلاس (سنرى الخطوه لاحقاً) من خلال وضعها كمعطى في الدالة Result.success.
تجهيز العمل للـ WorkManager
والان بعد ان قمنا بإنشاء كلاس خاصة بنا للـ WorkManager نحتاج الى انشاء بيانات هذا العمل وتجهيزه ثم جدولته.
اولاً تجهيز البيانات التي نريد ارسالها الى كلاسنا السابقه:
Data myData = new Data.Builder()
.putString("NAME_KEY", "Mohammad")
.putInt("AGE_KEY", 14)
.build();
تجيهز القيود او الشروط لعملنا:
Constraints constraints = new Constraints.Builder()
.setRequiresDeviceIdle(true)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
لاحظ التالي:
- سيعمل عملنا عندما يكون الجهاز في وضع الـ Idle ويجب كذلك ان يكون متصل بالانترنت.
تجهيز وانشاء عملنا لتشغيله لمرة واحدة فقط:
OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(MyJobManager.class)
.setInputData(myData)
.setConstraints(constraints)
.addTag("MY_WORK_MANAGER_TAG_ONE_TIME")
.build();
لاحظ التالي:
- قمنا بإنشاء عملنا بإستخدام كلاس الـ OneTimeWorkRequest وهذا يعني اننا نريد من علمنا ان يتنفذ فقط مرة واحدة.
- لاحظ ايضاً اعطاء الـ Builder كلاس الـ Work الذي انشئناها.
- ايضاً قمنا بإرفاق الـ Data بإستخدام setInputData.
- وكذلك قمنا بإرفاق القيود او الشروط بإستخدام setConstraints.
- واضفنا Tag لهذا العمل, حتى اذا اردنا ان نحدثه او نلغيه في المستقبل (تستطيع وضع Tag مشابه لإكثر من عمل).
- واخيراً قمنا ببنائه.
تجهيز وانشاء عملنا لتشغيله لإكثر من مرة:
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(MyJobManager.class, 12, TimeUnit.HOURS)
.setInputData(myData)
.setConstraints(constraints)
.addTag("MY_WORK_MANAGER_PERIODIC_TAG")
.build();
لاحظ التالي:
- قمنا بإنشاء علمنا في هذه المره بإستخدام كلاس الـ PeriodicWorkRequest لتشغيله لإكثر من مره.
- لاحظ ايضاً اعطاء الـ Builder كلاس الـ Work الذي انشئناها وايضاً الوقت المراد تكرار العمل (كل ١٢ ساعه)٠.
- اما ماتبقى فهو مشابه للمثال السابق.
جدولة العمل
الان نستطيع ارسال العمل الى النظام من خلال الـ Work Manager حتى يقوم بجدولته كالتالي:
WorkManager.getInstance().enqueue(oneTimeWorkRequest);
لاحظ التالي:
قمنا بإستخدام كلاس الـWorkManager ويتضح بإنها صممت بنمط الـ Singleton ثم نداء الدالة enqueue لوضع عملنا في قائمة النظام لتشغيله عندما يحين وقته وشروطه.
الغاء العمل
لإلغاء العمل نحتاج الى الحصول على الـ Id الخاص به, ثم الغائه بإستخدام الدالة cancelWorkById وفق الطريقة التالية:
UUID oneTimeWorkRequestId = oneTimeWorkRequest.getId();
WorkManager.getInstance().cancelWorkById(oneTimeWorkRequestId);
نستطيع ايضاً الغاء الاعمال كلها, او بعضها بإستخدام الـ Tag كالتالي:
WorkManager.getInstance().cancelAllWork();
WorkManager.getInstance().cancelAllWorkByTag("MY_WORK_MANAGER_TAG_ONE_TIME");
استقبال النتيجة من كلاس الـ Worker
بعد انجاز عملنا نستطيع استقبال النتيجة من خلال عنصر الـ LiveData (ماهي الـ LiveData؟) ,كالتالي:
WorkManager.getInstance().getWorkInfoByIdLiveData(oneTimeWorkRequestId).observe(this, new Observer<WorkInfo>() {
@Override
public void onChanged(@Nullable WorkInfo workInfo) {
if (workInfo != null && workInfo.getState().isFinished()){
String result = workInfo.getOutputData().getString("RESULT");
Log.d(TAG, "onChanged: " + result);
}
}
});
لاحظ التالي:
- قمنا بإستخدام الدالة getWorkInfoByIdLiveData ثم اعطيناها الـ Id الخاص بعملنا (انظر طريقة الحصول عليه في الخطوة السابقه بعنوان: الغاء العمل).
- ثم بعد ذلك اعطيناتها الـ Activity كـ this لإنها تتطلب LifeCyclerAware وايضاً اعطيناها متنصت ليراقب متى تجهز البيانات, ومن ثم نستطيع استخدامهم كما نريد.
ربط Chaining اكثر من عمل
اذا كان يوجد لدينا اعمال نريد تشغيلهم بالتسلسل نستطيع جدولتهم هكذا:
WorkManager.getInstance()
.beginWith(downLoadImageWorkRequest)
.then(saveDownloadedImageToDatabaseWorkRequest)
.then(cleanTempWorkRequest)
.enqueue();
اذا اردنا تشغيل بعضهم متوازي Parallel فيكون الوضع هكذا:
WorkManager.getInstance()
.beginWith(Arrays.asList(downloadImagesWorkRequest, downloadTextsWorkRequest, downloadLinksWorkRequest)) // Runs in Parallel.
.then(cleanTempWorkRequest)
.enqueue();
في هذا الدرس تعرفنا على الـ Work Manager ورئينا ابرز خصائصه ومميزاته.
رابط الكلاسات المستخدمه في هذا الدرس
- تم استخدام MyJobManager.java في Main8Activity.java.
للحصول على رابط المشروع راجع درس المقدمة.
المصادر والمراجع
- Android Developers Docs - Schedule tasks with WorkManager | Android Developers.
- Schedule tasks with WorkManager | Android Developers.
- Code Labs - Background Work with WorkManager.
للمزيد راجع درس المقدمة.
نهاية الدرس
لاتنسى تتبع الدرس والدورة كذلك لإشعارك عندما يتم التعديل على المتحوى او اضافة المزيد من المعلومات. ايضاً لاتنسى الاعجاب بالدرس ومشاركته مع الاخرين.
محتوى الدورة
الكلمات الدليلية
عن الدرس
0 إعجاب |
1 متابع |
0 مشاركة |
4189 مشاهدات |
منذ 5 سنوات |
التعليقات (0)
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !