OOZOU
تواصلوا معنا
العودة إلى المدونة

تشغيل Fragment للحصول على نتائج في Android

أضافت Google مؤخرًا قدرة جديدة إلى FragmentManager تجعله يعمل كمخزن مركزي لنتائج الـ fragments.

21 يونيو 2020
4 دقائق للقراءة
تشغيل Fragment للحصول على نتائج في Android

بصفتنا مطوّري Android، لا بد أننا جميعًا نعرف الدالة startActivityForResult. نستخدم هذه الدالة لتشغيل Activity جديدة واستلام النتائج في الـ Fragment أو الـ Activity الحالية، ما يسهّل التواصل بين الـ fragment والـ activity. لكن عندما تكون شاشات تطبيقي ممثّلة بـ Fragments، لا أستطيع استخدام startActivityForResult لتمرير النتائج بينها.

حتى وقت قريب، لم يكن هناك ما يشبه startActivityForResult عندما يتعلق الأمر بالتواصل بين الـ Fragments. لذلك كنت مضطرًا لإنشاء ViewModel مشترك بين الـ Fragments لأتمكن من تمرير البيانات ذهابًا وإيابًا بينها. أما القدرة الجديدة فتتيح لنا التعامل مع النتائج بين الـ fragments بطريقة مشابهة لتعاملنا معها بين الـ activities باستخدام startActivityForResult، لكنها مصمَّمة خصيصًا لسياق الـ fragment.

لحسن الحظ، أضافت Google مؤخرًا قدرة جديدة إلى عائلة الـ Fragment. وهناك طريقتان لتمرير البيانات ذهابًا وإيابًا بين الـ Fragments: الأولى باستخدام FragmentManager، والثانية باستخدام مكتبة Navigation component.

لنرَ إذن كيف نستخدم هذه القدرة الجديدة عمليًا. سأبني تطبيقًا بسيطًا لقائمة ملاحظات يتكوّن من Fragmentين باستخدام مكتبة Navigation component: أحدهما لعرض قائمة الملاحظات، والآخر لكتابة ملاحظة جديدة.

لنبدأ بإضافة التبعيات المهمة. وقت كتابة هذا المقال، كان أحدث إصدار من Fragment هو 1.3.0-alpha05.

def nav_version = "2.3.0-beta01"
def fragment_version = "1.3.0-alpha05"

implementation "androidx.fragment:fragment:$fragment_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"

implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"

وهذا هو الـ navigation graph الخاص بهذا المشروع.

الكود المصدري كاملًا متاح على https://github.com/BenBoonya/fragment-result

استخدام FragmentManager

الكود المصدري: https://github.com/BenBoonya/fragment-result/tree/using-fragment-manager

القدرة الجديدة التي أُضيفت إلى FragmentManager جعلت FragmentManager قادرًا على العمل كمخزن مركزي لنتائج الـ Fragments. ورغم أن الدالة لا تحمل اسم startFragmentForResult، فإنها تعمل بطريقة مشابهة لـ startActivityForResult. وبالمقتطف التالي يمكننا تمرير البيانات ذهابًا وإيابًا بين الـ Fragments بسهولة. وقد أُضيفت هذه القدرة منذ Fragment 1.3.0-alpha04.

لكي يستلم NoteListFragment النتيجة من AddNoteFragment، علينا تعيين result listener. لنلقِ نظرة على NoteListFragment.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    <em>setFragmentResultListener</em>(
        ADD_NOTE
    ) <strong>{ </strong>_, result <strong>->
        </strong>result.getString(NOTE)?.<em>let </em><strong>{ </strong>note <strong>->
            </strong>adapter.addItem(note)
        <strong>}
    }
</strong>}

كما ترون، تتوفر extension function باسم setFragmentResultListener، ونستلم النتيجة على شكل bundle. لننتقل إلى AddNoteFragment. نحتاج هنا إلى تعيين النتيجة، ويمكن فعل ذلك بسهولة كما يلي.

private fun navigateBack() {
    <em>setFragmentResult</em>(
        NoteListFragment.ADD_NOTE, <em>bundleOf</em>(
            NoteListFragment.NOTE <em>to </em>binding.editText.<em>text</em>.toString()
        )
    )
    <em>findNavController</em>().popBackStack()
}

الأمر الوحيد الذي يجب تذكّره هو أن عليكم تعيين النتيجة على FragmentManager نفسه باستخدام الـ requestKey نفسه. وإذا نظرنا عن قرب إلى الـ extension functions الخاصة بـ Fragment، سنرى أن كلًا من setFragmentResult وsetFragmentResultListener تستدعيان parentFragmentManager، كما في المقتطفين التاليين.

inline fun Fragment.setFragmentResultListener(
    requestKey: String,
    crossinline listener: ((resultKey: String, bundle: Bundle) -> Unit)
) {
    <em>parentFragmentManager</em>.<em>setFragmentResultListener</em>(requestKey, this, listener)
}
fun Fragment.setFragmentResult(
    requestKey: String,
    result: Bundle
) = <em>parentFragmentManager</em>.setFragmentResult(requestKey, result)

ومن الأمور الجديرة بالذكر أيضًا أنه لا يمكن أن يوجد إلا listener واحد ونتيجة واحدة لكل مفتاح. ففي مثالنا، إذا استدعينا setFragmentResult في AddNoteFragment أكثر من مرة، فسيرسل النظام أحدث نتيجة إلى NoteListFragment قبل إزالة AddNoteFragment من الـ back stack. وإذا كان AddNoteFragment child Fragment تابعًا لـ NoteListFragment، فكل ما نحتاج إليه هو تعيين الـ listener والنتيجة على childFragmentManager بدلًا من parentFragmentManager.

استخدام مكتبة Navigation component

الكود المصدري: https://github.com/BenBoonya/fragment-result/tree/using-navigation-component

لإرجاع النتائج إلى الوجهات السابقة، تستخدم مكتبة Navigation component SavedStateHandle، وهو key-value map يمكن استخدامه لتخزين البيانات واسترجاعها بشكل دائم حتى مع تغييرات الإعدادات (configuration changes) في NoteListFragment:

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    <em>findNavController</em>().<em>currentBackStackEntry</em>?.<em>savedStateHandle</em>?.getLiveData<String>(
        ADD_NOTE
    )?.observe(<em>viewLifecycleOwner</em>, <em>Observer </em><strong>{ </strong>note <strong>->
        </strong>adapter.addItem(note)
    <strong>}</strong>)
}

يوفّر savedStateHandle LiveData يمكننا وضع observer عليها للحصول على القيمة. في AddNoteFragment

<em>findNavController</em>().<em>previousBackStackEntry</em>?.<em>savedStateHandle</em>?.set(
    NoteListFragment.ADD_NOTE,
    binding.editText.<em>text</em>.toString()
)

هنا نعيّن القيمة في savedStateHandle الخاص بالـ back stack entry السابق، والذي يعود إلى NoteListFragment

الخلاصة

أتطلع بحماس إلى الإصدار المستقر من هذه الميزات. ففي رأيي، جعلت القدرات الجديدة في عائلة الـ Fragment العمل بمعمارية Single activity، التي تُمثَّل فيها كل الوجهات بـ Fragments، أسهل بكثير وأكثر جاذبية.

Related Articles

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

كيف أصمّم برمجيات؟ دليل المبتدئين لأصحاب الأعمال

تصميم البرمجيات عملية ممتعة لكنها معقدة، تتطلب الإبداع والتفكير المنطقي ومهارات حل المشكلات.

اقرأوا المزيد
مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

مستقبل الحوسبة الطرفية: ما تحتاج الشركات إلى معرفته

يتطور المشهد الرقمي بسرعة، وعلى الشركات أن تتكيّف لتواكب الطلب المتزايد على السرعة والكفاءة والمعالجة في الوقت الفعلي.

اقرأوا المزيد
مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

مستقبل قطاع التجزئة: الذكاء الاصطناعي والواقع المعزّز واتجاهات التحوّل الرقمي

يتطور قطاع التجزئة بوتيرة غير مسبوقة بفضل الذكاء الاصطناعي (AI) والواقع المعزّز (AR) وتقنيات التحوّل الرقمي. فلم تعد المتاجر التقليدية مجرد أماكن لبيع المنتجات، بل أصبحت متاجر ذكية وتفاعلية.

اقرأوا المزيد

Have a Project in Mind?

Let's discuss how we can help bring your ideas to life with our expertise in web and mobile development.

ابدأوا المحادثةhello@oozou.com
OOZOU Logo

بانكوك · سنغافورة · هونغ كونغ

X
Facebook
Instagram
LinkedIn
OOZOU Co., Ltd.
548 One City Centre
Ploenchit Road
Bangkok 10330
Thailand
+66 2544 0000
hello@oozou.com

الخدمات

  • تطوير الويب
  • وكلاء الذكاء الاصطناعي والذكاء الاصطناعي التوليدي
  • تطوير تطبيقات الجوال
  • تحليلات البيانات وهندستها
  • تصميم تجربة المستخدم وواجهته (UX/UI) وتصميم المنتجات
  • التحوّل الرقمي

الشركة

  • من نحن
  • الوظائف
  • المدونة
  • دراسات الحالة
  • عروض حية
  • تعلّمت اليوم
  • تواصل معنا

المزيد

  • القطاعات
  • شبكة الشركاء
© 2026 OOZOU. جميع الحقوق محفوظة.
سياسة الخصوصيةمدونة قواعد السلوكسياسة مكافحة الرشوة والفساد