تشغيل Fragment للحصول على نتيجة باستخدام Navigation Component
تعرّفوا على طريقة تشغيل Fragment للحصول على نتيجة دون عناء باستخدام Navigation Component.

مقدمة
تغيّر الكثير خلال السنتين الماضيتين في طريقة تطويرنا لتطبيقات Android. فلدينا الآن إطار أبسط لحقن التبعيات (dependency injection) هو Dagger-Hilt، ومكتبات AndroidX التي حسّنت استخدام كثير من مكوّنات Android، والـ coroutines التي أنقذتنا من جحيم الـ callbacks، ومكتبة ORM أفضل بكثير هي Room، ونعم، نظام تنقّل (navigation) أفضل بمراحل. ومن المشكلات الشائعة التي يواجهها المطوّرون خطأ 'unable to start activity'، الذي يظهر عادةً عندما يفشل التطبيق في تعيين NavController للـ activity. ودون أن نضيّع الكثير من وقتكم، لننتقل مباشرة إلى طريقة تشغيل fragment آخر للحصول على نتيجة منه.
فهم المشكلة
عند العمل مع Android Navigation Component، قد تواجهون استثناء IllegalStateException أثناء محاولة التنقل إلى fragment. يحدث هذا الخطأ عادةً لأن الـ fragment لا يملك NavController معيّنًا له. والـ NavController جزء أساسي من Navigation Component، فهو المسؤول عن إدارة التنقل بين الـ fragments. ومن دونه لا يستطيع Navigation Component تنفيذ عملية التنقل، فيظهر الخطأ.
العلاقة بين الـ Fragment والـ NavController
لكي يعمل Navigation Component بشكل صحيح، يجب أن يكون لكل fragment NavController معيّن. ويتحقق ذلك عادةً بإضافة الـ fragment إلى NavHostFragment، وهو نوع خاص من الـ fragments مصمَّم لاستضافة navigation graph. وعندما يكون الـ fragment جزءًا من NavHostFragment، يحصل تلقائيًا على نسخة الـ NavController، فيصبح التنقل سلسًا.
أما إذا لم يُضَف الـ fragment إلى NavHostFragment، فلن يكون له NavController. وغياب الـ NavController هو ما يطلق استثناء IllegalStateException، لأن Navigation Component لا يجد نسخة الـ NavController اللازمة للتنقل إلى الوجهة المطلوبة.
لنبدأ: start activity componentinfo
لنفترض أنكم تريدون الانتقال من Fragment A إلى Fragment B، وتريدون الحصول على نتيجة من Fragment B عند العودة إلى Fragment A. في هذه الحالة ستُعدّون Fragment A هكذا (وقد واجهت شخصيًا مشكلة في تمرير البيانات إلى الـ fragment السابق عندما كنت أعمل على مشروع مشابه): class FragmentA : Fragment override fun onViewCreatedview: View, savedInstanceState: Bundle? super.onViewCreatedview, savedInstanceState
class FragmentA : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
<strong>//Observe the result to be set by Fragment B in the stateHandle of the currentBackStackEntry
val currentBackStackEntry = findNavController().</strong><strong><em>currentBackStackEntry
</em></strong><strong>val savedStateHandle = currentBackStackEntry?.</strong><strong><em>savedStateHandle
</em></strong><strong>savedStateHandle?.getLiveData<String>(RESULT_FROM_FRAGMENT_B)
?.observe(currentBackStackEntry, Observer { result ->
print(result)
})</strong>
}
private fun navigateToFragmentB() {
val navDirection = FragmentADirection.actionFragmentAToFragmentB()
findNavController().navigate(navDirection)
}
companion object {
const val RESULT_FROM_FRAGMENT_B = "RESULT_FROM_FRAGMENT_B"
}
}
ثم تُعدّون Fragment B ليعيّن النتيجة التي يراقبها Fragment A
class FragmentB : Fragment() {
private fun navigateBackToFragmentA() {
<strong>//Setting the result in the stateHandle of the previousBackStackEntry before navigating back to Fragment A
//will allow Fragment A to access the result in the stateHandle of its currentBackStackEntry
val savedStateHandle = findNavController().</strong><strong><em>previousBackStackEntry</em></strong><strong>?.</strong><strong><em>savedStateHandle
</em></strong><strong>savedStateHandle?.set(FragmentA.RESULT_FROM_FRAGMENT_B, "result")
findNavController().navigateUp()</strong>
}
}
هذا كل شيء! يمكنكم بسهولة التنقل إلى أي fragment والحصول على النتيجة، عبر تعيينها في الـ stateHandle الخاص بـ previousBackStackEntry ومراقبتها في الـ stateHandle الخاص بـ currentBackStackEntry.
أفضل الممارسات
لتجنّب استثناء IllegalStateException وضمان تنقّل سلس بين الـ fragments، اتبعوا الممارسات التالية:
- استخدموا FragmentContainerView: بدلًا من استخدام FrameLayout في ملف الـ layout، اختاروا FragmentContainerView. فهذا الـ view مصمَّم خصيصًا لاحتواء NavHostFragment، ويسهّل تعيين نسخة الـ NavController.
- أنشئوا الـ NavController في onPostCreate(): في الـ MainActivity، استخدموا الدالة onPostCreate() لإنشاء نسخة الـ NavController. تُستدعى هذه الدالة بعد إنشاء الـ view الخاص بالـ activity، ما يضمن توفّر الـ NavController عند الحاجة إليه.
- اجعلوا الـ activity ترث من AppCompatActivity: تأكدوا من أن الـ activity الخاصة بكم ترث من AppCompatActivity، فهذا ضروري ليعمل Navigation Component بشكل صحيح.
- صحّحوا الإعدادات في Android Manifest: تأكدوا من أن ملف Android Manifest يتضمن الأذونات والـ activities والـ services والـ receivers والـ providers اللازمة. فهذا يساعد على تجنّب أي مشكلات متعلقة بالتنقل أثناء التشغيل.
باتباع هذه الممارسات، يمكنكم تجنّب استثناء IllegalStateException وضمان تنقّل تطبيقكم بسلاسة بين الـ fragments باستخدام Navigation Component.


