التنقل بين الشاشات
التنقل بين الشاشات
كل تطبيق Android غير بسيط يحتوي على أكثر من شاشة واحدة. يمنحك Android أداتين متكاملتين للتنقل بينها: واجهة Intent الكلاسيكية — المتاحة منذ Android 1.0 — ومكوّن Navigation، وهو مكتبة Jetpack تفرض هيكلًا قائمًا على الرسم البياني وقابلًا للتوقع على انتقالات الـ Fragment والـ Activity. عليك فهم الاثنين: فالـ Intents لا مفر منها (تتعامل مع التنقل بين التطبيقات وإجراءات النظام)، ومكوّن Navigation هو المعيار الحالي للتنقل داخل التطبيق.
Intents: أساس التنقل في Android
الـ Intent هو كائن رسالة يصف الإجراء الذي تريد تنفيذه. حين تمرّره إلى startActivity()، يعثر نظام Android على مكوّن مناسب للتعامل معه ويبدأ تشغيله.
هناك نوعان من الـ Intent:
- Intent صريح (Explicit) — تُسمّي فيه فئة الـ
Activityالمستهدفة بالاسم. يُستخدم للتنقل داخل التطبيق. - Intent ضمني (Implicit) — تُعلن فيه إجراءً (مثل
Intent.ACTION_VIEW) وتترك للنظام مهمة إيجاد تطبيق قادر على التعامل معه. يُستخدم لفتح رابط في المتصفح، أو مشاركة محتوى، أو إجراء مكالمة، وما إلى ذلك.
Intents الصريحة: الانتقال إلى Activity أخرى
النمط الأدنى لفتح DetailActivity من MainActivity بسيط:
المعامل الأول لمُنشئ الـ Intent هو Context — هنا يُشير this إلى الـ Activity الحالية التي تُعدّ Context بحد ذاتها. المعامل الثاني هو كائن الفئة الخاص بالـ Activity الوجهة.
startActivity() يدفع الـ Activity الجديدة إلى المكدس الخلفي. حين يضغط المستخدم زر الرجوع أو يستدعي finish()، تُزال الـ Activity العلوية ويستأنف نشاط العمل السابق. يُدار هذا المكدس تلقائيًا ونادرًا ما تحتاج إلى التدخل فيه مباشرةً.
تمرير البيانات عبر Extras
تحمل الـ Intents حزمة Bundle من أزواج المفاتيح/القيم تُسمى extras. استخدمها لإرسال بيانات أساسية إلى الـ Activity الوجهة:
public static final String في فئة الـ Activity الوجهة — مثلاً DetailActivity.EXTRA_ITEM_ID. يُشير المُرسِل والمُستقبِل حينها إلى نفس الثابت مما يُزيل أخطاء الكتابة.
Intents الضمنية: مغادرة تطبيقك
لفتح صفحة ويب لا تكتب متصفحًا — بل تُطلق Intent ضمنيًا ويوجّهه النظام إلى المتصفح المثبّت:
قبل استدعاء startActivity() على Intent ضمني يجب التحقق من وجود تطبيق قادر على التعامل معه، وإلا فستواجه استثناء ActivityNotFoundException:
استقبال نتيجة: ActivityResult API
أحيانًا تفتح نشاطًا ثانيًا وتحتاج نتيجة في المقابل — كمنتقي صور أو شاشة إعدادات. الطريقة الحديثة (التي تحلّ محل startActivityForResult المهجور) تستخدم ActivityResultLauncher:
في PickerActivity، استدع setResult() قبل finish():
startActivityForResult() أبدًا. هذه الدالة مهجورة في API 29+. سجّل دائمًا ActivityResultLauncher في onCreate() — تسجيله في مرحلة لاحقة (بعد onStart()) يُطلق استثناء IllegalStateException.
مكوّن Navigation
حين يحتوي تطبيقك على شاشات كثيرة، تصبح إدارة شبكة من الـ Intents الصريحة وأعلام المكدس الخلفي عرضةً للأخطاء. يعالج مكوّن Jetpack Navigation هذا من خلال تمثيل تنقل تطبيقك كـرسم بياني للتنقل تصريحي — ملف XML يُدرج الوجهات (الـ Fragments) والإجراءات (الحواف) التي تربطها.
أضف التبعية إلى build.gradle (الوحدة app):
إنشاء رسم بياني للتنقل
انقر بزر الماوس الأيمن على res < New < Android Resource File، اختر النوع Navigation، وسمّه nav_graph.xml. في محرر XML أعلن الوجهات والإجراءات بينها:
استضافة الرسم البياني: NavHostFragment
يحتاج تخطيط الـ Activity الرئيسية إلى NavHostFragment — الحاوية التي تتبادل فيها الـ Fragments عند التنقل:
تعترض app:defaultNavHost="true" زر الرجوع لنظام التشغيل، فيتولّى مكوّن Navigation إدارة إزالة عناصر المكدس الخلفي تلقائيًا.
التنقل عبر NavController
داخل أي Fragment مستضاف في الرسم البياني، احصل على NavController واستدع navigate() بمعرّف الإجراء:
في DetailFragment، استرجع المعطى من getArguments():
ListFragmentDirections.actionListToDetail(101)). يُزيل هذا مفاتيح الـ Bundle المكتوبة كنصوص ويمنحك أخطاء وقت الترجمة عند وجود أنواع معطيات خاطئة.
Intent مقابل مكوّن Navigation: متى تستخدم كلًّا منهما
- استخدم Intents في: بدء تطبيق آخر (متصفح، كاميرا، هاتف)، والروابط العميقة من الإشعارات، والتنقل بين الـ Activities الرئيسية (مثلاً شاشة الإعداد الأوّلي ← التطبيق الرئيسي).
- استخدم مكوّن Navigation في: جميع انتقالات الشاشة داخل التطبيق ضمن Activity واحد يستضيف عدة Fragments. يتعامل مع المكدس الخلفي والانتقالات المتحركة وعناوين URL للروابط العميقة في مكان واحد.
الخلاصة
الـ Intents هي نظام الرسائل في Android — تُسمّي الـ Intents الصريحة فئةً بالاسم، بينما تُعلن الـ Intents الضمنية إجراءً وتترك للنظام مهمة التوجيه. تُعدّ واجهة ActivityResultLauncher الطريقة الحالية لاستقبال البيانات من شاشة أخرى. أما مكوّن Jetpack Navigation فيحلّ محل مجموعة مشتتة من استدعاءات الـ Intent بواسطة رسم بياني تنقل واحد: أعلن وجهاتك في XML، واستضفها في NavHostFragment، وتنقّل باستدعاء NavController.navigate() مع معرّف الإجراء. يُغطّي هذان الأسلوبان معًا كل سيناريو تنقل ستواجهه في تطبيق Android حقيقي.