Handler() أصبح قديمًا: ماذا الآن؟ نظرة إلى عام 2025
\n\nإذا كنت قد كتبت أي كود لنظام Android من قبل، فمن المحتمل أنك استخدمت Handler() للتبديل بين الخيوط أو المهام المؤجلة أو تحديث واجهة المستخدم. هذه الفئة الكلاسيكية القديمة كانت معنا منذ الإصدارات الأولى لنظام Android. لكن في 2024-2025، أعلنت Google رسميًا أن المُنشئ Handler() مُهمَل (deprecated). آلاف المطورين على Stack Overflow يسألون: «ماذا أستخدم الآن بعد أن أصبح Handler() مهملاً؟»
في هذه المقالة، سنفهم لماذا أصبح Handler() مهملاً، وما هي البدائل التي يقدمها Android في 2025، والأهم من ذلك — كيفية كتابة كود حديث ونظيف بلغة Kotlin لن يسبب الصداع لقائد فريقك. هيا بنا!
لماذا أصبح Handler() مهملاً؟
\n\nفئة Handler نفسها لم تختفِ. المُهمَل هو تحديدًا المُنشئ بدون وسائط (Handler()) وتحميلاته الزائدة التي كانت تنشئ ضمنيًا Looper من الخيط الحالي. المشكلة أن هذا السلوك:
- \n
- ضمني وغير آمن — إذا استدعيت
Handler()في خيط خلفي ليس لديهLooper، ستحصل علىRuntimeException. \n - يعقد الاختبار —
Handlerمرتبط بشدة بدورة حياة الخيوط، مما يجعل اختبارات الوحدة صداعًا. \n - عفا عليه الزمن معنويًا — ظهرت أدوات أكثر حداثة وتصريحية: الكوروتينات،
HandlerThread(بشكل صريح) وLiveData. \n
توصي Google بتمرير Looper بشكل صريح إلى المُنشئ، أو استخدام البدائل. دعنا نرى ما الذي حل محله بالضبط.
البديل رقم 1: Looper صريح (أسهل إصلاح)
\n\nإذا كنت لا تريد إعادة كتابة كل الكود، أسرع طريقة لإزالة التحذير من الإهمال هي تمرير Looper بشكل صريح. للخيط الرئيسي (UI thread) استخدم Looper.getMainLooper().
// الكود القديم (مُهمَل)\nval handler = Handler()\n\n// الكود الجديد (2025)\nval handler = Handler(Looper.getMainLooper())\n\n// أو للخيط الخلفي:\nval handler = Handler(Looper.myLooper()) // انتبه: قد يكون null!\n\n\nهذا لن يحل كل المشاكل، لكنه سيزيل تحذير المترجم. ومع ذلك، للمشاريع الجادة، من الأفضل الانتقال إلى الكوروتينات.
\n\nالبديل رقم 2: Kotlin Coroutines (موصى به من Google)
\n\nمنذ 2021، توصي Google رسميًا باستخدام Kotlin Coroutines للعمليات غير المتزامنة. في 2025، أصبح هذا هو المعيار الصناعي. لماذا الكوروتينات أفضل من Handler؟
- \n
- خفيفة الوزن — آلاف الكوروتينات لا تمنع الخيوط. \n
- التزامن المنظم — الإلغاء التلقائي عند انتهاء دورة الحياة. \n
- قابلية القراءة — الكود يبدو متزامنًا، بدون استدعاءات رد. \n
- قابلية الاختبار —
runBlockingوTestCoroutineDispatcherلاختبارات الوحدة. \n
إليك كيفية استبدال المهام النموذجية لـ Handler بالكوروتينات:
استبدال postDelayed (مهمة مؤجلة)
\n\n// الطريقة القديمة مع Handler\nval handler = Handler(Looper.getMainLooper())\nhandler.postDelayed({\n // التنفيذ بعد ثانيتين\n}, 2000)\n\n// الطريقة الجديدة مع Coroutines\nlifecycleScope.launch {\n delay(2000) // لا يمنع الخيط!\n // التنفيذ بعد ثانيتين\n}\n\n\nاستبدال post (التبديل إلى خيط واجهة المستخدم)
\n\n// الطريقة القديمة\nhandler.post {\n textView.text = "مرحبًا من الخيط الخلفي"\n}\n\n// الطريقة الجديدة\nlifecycleScope.launch(Dispatchers.Main) {\n textView.text = "مرحبًا من الكوروتين"\n}\n\n\nاستبدال removeCallbacks (إلغاء المهمة)
\n\n// الطريقة القديمة\nval runnable = Runnable { /*...*/ }\nhandler.postD