دليل WorkManager في Kotlin: شرح شامل مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة عن WorkManager في Kotlin

WorkManager هي مكتبة من Google لنظام Android، مصممة لتنفيذ المهام الخلفية التي يجب ضمان إنجازها حتى عند إعادة تشغيل الجهاز أو إغلاق التطبيق. وهي جزء من Android Jetpack وتوفر واجهة برمجة تطبيقات (API) بسيطة وموثوقة لجدولة المهام المؤجلة والدورية والمرة الواحدة.

الهدف الرئيسي لـ WorkManager هو استبدال الآليات القديمة للعمل في الخلفية مثل Service أو AsyncTask، وضمان التوافق مع إصدارات Android المختلفة (من API 14+). تختار المكتبة تلقائيًا الطريقة المثلى لتنفيذ المهمة: JobScheduler (API 23+)، AlarmManager + BroadcastReceiver (الإصدارات الأقدم)، أو Firebase JobDispatcher (إذا تم تضمينه).

WorkManager مثالي لسيناريوهات مثل: مزامنة البيانات مع الخادم، إرسال التحليلات، تحميل الملفات، معالجة الصور، النسخ الاحتياطي، إرسال الإشعارات الفورية، وأي مهام أخرى لا تتطلب تنفيذًا فوريًا ولكن يجب إكمالها في أقرب وقت.

تثبيت WorkManager

لا يتم تثبيت WorkManager عبر pip أو npm، لأنها مكتبة لنظام Android (Kotlin/Java). لإضافتها إلى مشروعك، يجب تعديل ملف build.gradle (على مستوى الوحدة).

الخطوة 1: افتح ملف build.gradle الخاص بوحدتك (app/build.gradle).

الخطوة 2: أضف التبعية في كتلة dependencies:

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.9.0"
}

الخطوة 3: قم بمزامنة المشروع (Sync Now).

إذا كنت تستخدم Kotlin DSL، فستبدو التبعية كالتالي:

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.0")
}

هام: الإصدار 2.9.0 هو الأحدث وقت كتابة هذا المقال. يُوصى بالتحقق من أحدث إصدار على الموقع الرسمي Android Developers.

بداية سريعة مع مثال كود

لنلقِ نظرة على مثال بسيط: إنشاء مهمة خلفية تطبع سجلًا في Logcat.

الخطوة 1: إنشاء كلاس Worker

import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters

class SimpleWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

    override fun doWork(): Result {
        Log.d("SimpleWorker", "تم تنفيذ المهمة الخلفية!")
        // هنا يمكن تنفيذ أي عملية طويلة
        return Result.success()
    }
}

الخطوة 2: جدولة تنفيذ المهمة

import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager

val workRequest = OneTimeWorkRequestBuilder<SimpleWorker>()
    .build()

WorkManager.getInstance(context).enqueue(workRequest)

بعد استدعاء enqueue()، سيتم تنفيذ المهمة في أقرب وقت (عادةً خلال بضع ثوانٍ، إذا لم تكن هناك قيود).

الطرق والوظائف الأساسية لـ WorkManager

1. OneTimeWorkRequestBuilder

الوظيفة: إنشاء طلب تنفيذ لمرة واحدة للمهمة. يتم تنفيذ المهمة مرة واحدة ثم تُحذف من قائمة الانتظار.

المعلمات:

  • workerClass (إجباري) — الكلاس الذي يرث من Worker أو CoroutineWorker.
  • setInitialDelay() — تأخير قبل التنفيذ (بالمللي ثانية).
  • setConstraints() — القيود (مثل الاتصال بالإنترنت).
  • addTag() — علامة لتجميع المهام.
  • setInputData() — بيانات الإدخال للـ Worker.

مثال:

val request = OneTimeWorkRequestBuilder<SimpleWorker>()
    .setInitialDelay(5000)
    .addTag("sync")
    .build()

2. PeriodicWorkRequestBuilder

الوظيفة: إنشاء طلب تنفيذ دوري للمهمة. يتم تنفيذ المهمة بشكل متكرر على فترات زمنية محددة.

المعلمات:

  • repeatInterval (إجباري) — الفاصل الزمني بين التنفيذات (بالثواني).
  • repeatIntervalTimeUnit — وحدة الوقت (افتراضيًا TimeUnit.MILLISECONDS).
  • setConstraints() — القيود (مثل الشحن).

مثال:

val periodicRequest = PeriodicWorkRequestBuilder<SimpleWorker>(15, TimeUnit.MINUTES)
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build())
    .build()

3. Constraints

الوظيفة: تحديد الشروط التي يجب توفرها لتنفيذ المهمة.

الأنواع:

  • NetworkType.CONNECTED — يتطلب اتصالاً بالإنترنت.
  • NetworkType.UNMETERED — يتطلب اتصالاً غير محدود (Wi-Fi).
  • BatteryNotLow — يتطلب أن تكون البطارية غير منخفضة.
  • StorageNotLow — يتطلب أن تكون مساحة التخزين غير منخفضة.
  • DeviceIdle — يتطلب أن يكون الجهاز في وضع الخمول.

مثال:

val constraints = Constraints.Builder()
    .setRequiredNetworkType(NetworkType.CONNECTED)
    .setRequiresBatteryNotLow(true)
    .build()

4. WorkManager.enqueue()

الوظيفة: إضافة المهمة إلى قائمة الانتظار للتنفيذ.

المعلمات:

  • workRequest (إجباري) — كائن WorkRequest.
  • existingWorkPolicy — سياسة التعامل مع المهام الموجودة (اختياري).

مثال:

WorkManager.getInstance(context).enqueue(workRequest)

5. WorkManager.cancelWorkById()

الوظيفة: إلغاء مهمة محددة باستخدام معرفها.

مثال:

WorkManager.getInstance(context).cancelWorkById(workRequest.id)

6. WorkManager.getWorkInfoByIdLiveData()

الوظيفة: مراقبة حالة المهمة باستخدام LiveData.

مثال:

WorkManager.getInstance(context).getWorkInfoByIdLiveData(workRequest.id)
    .observe(this) { workInfo ->
        if (workInfo.state == WorkInfo.State.SUCCEEDED) {
            Log.d("WorkManager", "تمت المهمة بنجاح")
        }
    }

أمثلة عملية متقدمة

مثال 1: مزامنة البيانات مع الخادم

class SyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            val api = RetrofitClient.instance
            val response = api.syncData()
            if (response.isSuccessful) {
                Result.success()
            } else {
                Result.retry()
            }
        } catch (e: Exception) {
            Result.failure()
        }
    }
}

مثال 2: تحميل ملف مع إظهار الإشعار

class DownloadWorker(context: Context, params: WorkerParameters) : Worker(context, params) {

    override fun doWork(): Result {
        val url = inputData.getString("file_url") ?: return Result.failure()
        // تنفيذ التحميل
        showNotification("تم التحميل بنجاح")
        return Result.success()
    }

    private fun showNotification(message: String) {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        // إنشاء الإشعار
    }
}

نصائح وحيل مهمة

  • استخدم CoroutineWorker بدلاً من Worker للاستفادة من coroutines في Kotlin.
  • تأكد من إضافة android:name="androidx.work.WorkManagerInitializer" في ملف AndroidManifest.xml إذا كنت تستخدم تهيئة مخصصة.
  • اختبر المهام على إصدارات Android المختلفة لضمان التوافق.
  • استخدم setBackoffCriteria() لتحديد استراتيجية إعادة المحاولة في حالة الفشل.

توصيات