---
title: "تشغيل Fragment للحصول على نتائج في Android"
description: "أضافت Google مؤخرًا قدرة جديدة إلى FragmentManager تجعله يعمل كمخزن مركزي لنتائج الـ fragments."
canonical: https://oozou.com/ar/blog/starting-a-fragment-for-results-in-android-46
locale: ar
date: 2020-06-21
author: "OOZOU Team"
---

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

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

Published: 2020-06-21 · Author: OOZOU Team (Engineering) · 4 min read

بصفتنا مطوّري 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**.

```groovy
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](https://github.com/BenBoonya/fragment-result)

# استخدام FragmentManager

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

القدرة الجديدة التي أُضيفت إلى **FragmentManager** جعلت **FragmentManager** قادرًا على العمل كمخزن مركزي لنتائج الـ Fragments. ورغم أن الدالة لا تحمل اسم **startFragmentForResult**، فإنها تعمل بطريقة مشابهة لـ **startActivityForResult**. وبالمقتطف التالي يمكننا تمرير البيانات ذهابًا وإيابًا بين الـ Fragments بسهولة. وقد أُضيفت هذه القدرة منذ [Fragment 1.3.0-alpha04](https://developer.android.com/jetpack/androidx/releases/fragment#1.3.0-alpha04).

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

```kotlin
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**. نحتاج هنا إلى تعيين النتيجة، ويمكن فعل ذلك بسهولة كما يلي.

```kotlin
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**، كما في المقتطفين التاليين.

```kotlin
inline fun Fragment.setFragmentResultListener(
    requestKey: String,
    crossinline listener: ((resultKey: String, bundle: Bundle) -> Unit)
) {
    <em>parentFragmentManager</em>.<em>setFragmentResultListener</em>(requestKey, this, listener)
}
```
```kotlin
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](https://github.com/BenBoonya/fragment-result/tree/using-navigation-component)

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

```kotlin
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**

```kotlin
<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، أسهل بكثير وأكثر جاذبية.

---

Contact OOZOU: hello@oozou.com · +66 2544 0000 · https://oozou.com/ar/contact

More for AI agents: https://oozou.com/llms.txt · every page has a markdown twin at its URL plus ".md"
