FragmentManager
هو
الفئة المسؤولة عن تنفيذ الإجراءات على أجزاء التطبيق، مثل
مثل إضافتها أو إزالتها أو استبدالها وإضافتها إلى الحزمة الخلفية.
قد لا تتفاعل مع "FragmentManager
" مباشرةً أبدًا إذا كنت تستخدم
مكتبة Jetpack Navigation، نظرًا لأنها تعمل مع
FragmentManager
نيابةً عنك. ومع ذلك، فإن أي تطبيق يستخدم الأجزاء
استخدام FragmentManager
على مستوى ما، لذلك من المهم فهم ما
عليها وكيف تعمل.
تتناول هذه الصفحة ما يلي:
- كيفية الوصول إلى
FragmentManager
- دور
FragmentManager
في ما يتعلق بأنشطتك وأجزائك. - كيفية إدارة الحزمة الخلفية باستخدام "
FragmentManager
" - كيفية توفير البيانات والتبعيات للأجزاء.
الوصول إلى FragmentManager
يمكنك الوصول إلى FragmentManager
من نشاط أو من جزء.
FragmentActivity
وفئاتها الفرعية، مثل
AppCompatActivity
,
يمكنك الوصول إلى FragmentManager
من خلال
getSupportFragmentManager()
.
يمكن أن تستضيف الأجزاء جزءًا فرعيًا واحدًا أو أكثر. داخل المنشأة
جزء، يمكنك الحصول على مرجع إلى FragmentManager
الذي يدير
أطفال الجزء من خلال
getChildFragmentManager()
إذا كنت بحاجة إلى الوصول إلى مضيفه FragmentManager
، يمكنك استخدام
getParentFragmentManager()
فيما يلي بعض الأمثلة لمعرفة العلاقات بين
الأجزاء ومضيفاتها والمثيلات المرتبطة بـ FragmentManager
مع كل منها.
يوضح الشكل 1 مثالين، لكل منهما مضيف نشاط واحد. تشير رسالة الأشكال البيانية
نشاط مضيف في كلا المثالين يعرض التنقل عالي المستوى إلى
المستخدم بصفته
BottomNavigationView
يكون المسئول عن استبدال جزء المضيف بأجزاء
الشاشات في التطبيق. يتم تنفيذ كل شاشة كجزء منفصل.
يستضيف جزء المضيف في المثال 1 جزأين فرعيين إنشاء شاشة عرض مقسمة. يستضيف جزء المضيف في المثال 2 جزء فرعي واحد يتألف من جزء العرض عرض التمرير السريع.
وفي ضوء هذا الإعداد، يمكنك اعتبار أن كل مضيف لديه FragmentManager
المرتبطة بها التي تدير أجزائها الفرعية. يمكنك توضيح ذلك في
الشكل 2 مع تعيينات الخصائص بين supportFragmentManager
،
parentFragmentManager
وchildFragmentManager
تعتمد سمة FragmentManager
المناسبة التي يجب الإشارة إليها على المكان الذي
يكون موقع الاتصال في التسلسل الهرمي للأجزاء إلى جانب مدير الأجزاء
الذي تحاول الوصول إليه.
بعد إضافة إشارة إلى FragmentManager
، يمكنك استخدامها
معالجة الأجزاء التي يتم عرضها للمستخدم.
الأجزاء الثانوية
بشكل عام، يتكوّن تطبيقك من رقم واحد أو صغير.
الأنشطة في مشروع تطبيقك، حيث يمثل كل نشاط
مجموعة من الشاشات ذات الصلة. قد يوفر النشاط نقطة لوضعها
التنقّل على المستوى الأعلى ومكان لتحديد نطاق عناصر ViewModel
وحالة العرض الأخرى
بين الأجزاء. يمثّل الجزء وجهة فردية في
التطبيق.
إذا أردت إظهار أجزاء متعدّدة في آنٍ واحد، كما هو الحال في العرض المقسّم أو لوحة التحكم، يمكنك استخدام الأجزاء الفرعية التي تديرها جزء الوجهة وإدارة الأجزاء الفرعية التابعة له.
في ما يلي حالات الاستخدام الأخرى للأجزاء الثانوية:
- شرائح الشاشة،
استخدام
ViewPager2
في جزء رئيسي لإدارة سلسلة من العناصر الثانوية طرق عرض مجزأة. - التنقُّل الفرعي ضمن مجموعة من الشاشات ذات الصلة
- يستخدم التنقّل في Jetpack الأجزاء الثانوية كوجهات فردية. إنّ
يستضيف النشاط مستخدم أحد الوالدين
NavHostFragment
ويملأ المساحة. مع أجزاء وجهة فرعية مختلفة أثناء تنقّل المستخدمين تطبيقك.
استخدام FragmentManager
ويدير FragmentManager
تسلسل استدعاء الدوال البرمجية للجزء. في وقت التشغيل،
يمكن لـ FragmentManager
تنفيذ عمليات حزمة الخلفية مثل الإضافة أو الإزالة
الأجزاء استجابةً لتفاعلات المستخدم. تكون كل مجموعة من التغييرات
الالتزام معًا كوحدة واحدة تسمى
FragmentTransaction
للحصول على مناقشة أكثر تفصيلاً حول معاملات التجزئة، راجع
دليل المعاملات المجزأة.
عندما ينقر المستخدم على زر الرجوع في جهازه، أو عند الاتصال
FragmentManager.popBackStack()
،
تنبثق معاملة الجزء العلوي من الحزمة. إذا لم يكن هناك أجزاء أخرى
المعاملات على المكدس، وإذا كنت لا تستخدم الأجزاء الفرعية،
الحدث حتى النشاط. في حال استخدام الأجزاء الثانوية، يُرجى مراجعة
اعتبارات خاصة للأجزاء التابعة للأطفال والأجزاء التابعة.
عند الاتصال
addToBackStack()
إجراء معاملة، يمكن أن تتضمن المعاملة أي عدد من
العمليات، مثل إضافة أجزاء متعددة أو استبدال الأجزاء في
الأخرى.
عندما يتم تمييز المكدس الخلفي، يتم
العمليات العكسية كإجراء بسيط واحد. ومع ذلك، إذا التزمت
المعاملات الإضافية قبل إجراء مكالمة popBackStack()
، وإذا
لم تستخدم addToBackStack()
للمعاملة، فإن هذه العمليات
لا تتراجع. لذلك، مع تضمين علامة FragmentTransaction
واحدة، تجنَّب
المعاملات المتداخلة التي تؤثر على الحزمة الخلفية مع تلك التي لا تؤثر عليها.
إجراء معاملة
لعرض جزء ضمن حاوية تصميم، استخدِم السمة FragmentManager
.
لإنشاء FragmentTransaction
. ضمن المعاملة، يمكنك بعد ذلك
إجراء
add()
أو replace()
العملية في الحاوية.
على سبيل المثال، قد يظهر FragmentTransaction
البسيط على النحو التالي:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("name") // Name can be null }
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack("name") // Name can be null .commit();
في هذا المثال، يستبدل ExampleFragment
الجزء، إن وجد،
حاليًا في حاوية التخطيط المحددة بواسطة
معرّف "R.id.fragment_container
" يمكن توفير فئة الجزء
replace()
تتيح الطريقة FragmentManager
معالجة إنشاء مثيل باستخدام
FragmentFactory
لمزيد من المعلومات، يُرجى الاطّلاع على المقالة توفير اعتماديات للأجزاء.
.
setReorderingAllowed(true)
تحسين تغييرات حالة الأجزاء المتضمنة في المعاملة
بحيث تعمل الرسوم المتحركة والانتقالات بشكل صحيح. لمزيد من المعلومات حول
والتنقل باستخدام الرسوم المتحركة والتحولات، راجع
معاملات التجزئة
التنقل بين الأجزاء باستخدام الصور المتحركة.
إجراء المكالمات
addToBackStack()
ينفّذ المعاملة في الحزمة الخلفية. ويمكن للمستخدم لاحقًا عكس
للمعاملة وإعادة الجزء السابق من خلال النقر على زر الرجوع
. إذا أضفت أجزاءً متعددة أو أزلتها داخل جزء واحد
يتم التراجع عن جميع هذه العمليات عندما يتم تنفيذ العمليات
فرقعة. الاسم الاختياري المُقدم في المكالمة addToBackStack()
يمنح
القدرة على العودة إلى معاملة معينة باستخدام
popBackStack()
في حال عدم الاتصال بـ "addToBackStack()
" عند إجراء معاملة
عند إزالة جزء، ثم يتم إتلاف الجزء الذي تمت إزالته عند
إتمام العملية، ولا يمكن للمستخدم الرجوع إليها. إذا كنت
عند إزالة جزء، يتم استدعاء addToBackStack()
،
STOPPED
فقط ويصبح لاحقًا RESUMED
عند رجوع المستخدم إلى الصفحة السابقة. طريقة العرض
يتم إتلافه في هذه الحالة. لمزيد من المعلومات، يُرجى مراجعة
دورة حياة التجزئة:
البحث عن جزء حالي
يمكنك الحصول على مرجع إلى الجزء الحالي داخل حاوية تصميم.
باستخدام
findFragmentById()
يمكنك استخدام findFragmentById()
للبحث عن جزء إما من خلال رقم التعريف المحدّد عند
تضخم من XML أو من خلال معرّف الحاوية عند إضافتها في
FragmentTransaction
وفي ما يلي مثال لذلك:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentById(R.id.fragment_container);
بدلاً من ذلك، يمكنك تعيين علامة فريدة للجزء والحصول على
الرجوع باستخدام
findFragmentByTag()
يمكنك تحديد علامة باستخدام سمة XML android:tag
على الأجزاء التي
ضمن التنسيق أو أثناء السمة add()
أو replace()
داخل FragmentTransaction
.
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container, "tag") setReorderingAllowed(true) addToBackStack(null) } ... val fragment: ExampleFragment = supportFragmentManager.findFragmentByTag("tag") as ExampleFragment
Java
FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null, "tag") .setReorderingAllowed(true) .addToBackStack(null) .commit(); ... ExampleFragment fragment = (ExampleFragment) fragmentManager.findFragmentByTag("tag");
اعتبارات خاصة للأجزاء الثانوية والأجزاء التابعة
يمكن لـ FragmentManager
واحد فقط التحكّم في الحزمة الخلفية للجزء.
في أي وقت محدد. إذا كان تطبيقك يعرض أجزاءً متعددة تابعة على
الشاشة في الوقت نفسه، أو إذا كان تطبيقك يستخدم أجزاءً فرعية،
تم تصميم FragmentManager
ليتعامل مع شريط التنقّل الأساسي في تطبيقك.
لتحديد جزء التنقل الأساسي داخل معاملة مجزأة،
طلب
setPrimaryNavigationFragment()
في العملية، وتمريره في مثيل الجزء الذي
childFragmentManager
لديه التحكم الأساسي.
ضع في اعتبارك هيكل التنقل كسلسلة من الطبقات، مع النشاط باعتبارها الطبقة الخارجية، تلف كل طبقة من الأجزاء الثانوية بالأسفل. تحتوي كل طبقة على جزء تنقل أساسي واحد.
مسلسل When the Back وقوع الحدث، تتحكم الطبقة الأعمق في سلوك التنقل. بمجرد في الطبقة الأعمق، لا تحتوي على معاملات مجزأة يمكن العودة منها، ويعود التحكم إلى الطبقة التالية، وتتكرر هذه العملية حتى الوصول إلى النشاط.
فعند عرض جزأين أو أكثر في نفس الوقت، أحدهما هو جزء التنقل الأساسي. تعيين جزء لأن جزء التنقل الأساسي يزيل التصنيف من الجزء السابق . باستخدام المثال السابق، إذا قمت بتعيين جزء التفاصيل جزء التنقل الأساسي، تتم إزالة تعيين الجزء الرئيسي.
دعم عدة حزم خلفية
في بعض الحالات، قد يحتاج تطبيقك إلى دعم عدة حِزم خلفية. من الشائع
على سبيل المثال، إذا كان تطبيقك يستخدم شريط تنقل سفليًا. FragmentManager
السماح
يمكنك دعم عدة حزم خلفية باستخدام saveBackStack()
restoreBackStack()
طريقة تتيح لك هذه الطرق التبديل بين الروابط
عن طريق حفظ مكدّس خلفي واحد واستعادة مكدّس آخر.
تعمل ميزة saveBackStack()
بشكل مشابه للاتصال بـ popBackStack()
باستخدام الخيار الاختياري.
مَعلمة name
: المعاملة المحدّدة وجميع المعاملات التي تليها في
المكدس. ويكمن الفرق في أن saveBackStack()
يحفظ
لجميع الأجزاء في القسم
المعاملات.
على سبيل المثال، لنفترض أنك أضفت في وقت سابق جزءًا إلى المكدس الخلفي عن طريق
الالتزام بـ FragmentTransaction
باستخدام addToBackStack()
، كما هو موضّح في القسم
المثال التالي:
Kotlin
supportFragmentManager.commit { replace<ExampleFragment>(R.id.fragment_container) setReorderingAllowed(true) addToBackStack("replacement") }
Java
supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ExampleFragment.class, null) // setReorderingAllowed(true) and the optional string argument for // addToBackStack() are both required if you want to use saveBackStack() .setReorderingAllowed(true) .addToBackStack("replacement") .commit();
في هذه الحالة، يمكنك حفظ هذه العملية التي تم تقسيمها وحالة
ExampleFragment
عن طريق الاتصال بـ saveBackStack()
:
Kotlin
supportFragmentManager.saveBackStack("replacement")
Java
supportFragmentManager.saveBackStack("replacement");
يمكنك استدعاء restoreBackStack()
بنفس معلمة الاسم لاستعادة جميع
المعاملات المنبثقة وجميع الأجزاء المحفوظة تنص على ما يلي:
Kotlin
supportFragmentManager.restoreBackStack("replacement")
Java
supportFragmentManager.restoreBackStack("replacement");
توفير التبعيات للأجزاء
عند إضافة جزء، يمكنك إنشاء مثيل للجزء يدويًا
وإضافته إلى FragmentTransaction
.
Kotlin
fragmentManager.commit { // Instantiate a new instance before adding val myFragment = ExampleFragment() add(R.id.fragment_view_container, myFragment) setReorderingAllowed(true) }
Java
// Instantiate a new instance before adding ExampleFragment myFragment = new ExampleFragment(); fragmentManager.beginTransaction() .add(R.id.fragment_view_container, myFragment) .setReorderingAllowed(true) .commit();
عند إتمام معاملة التجزئة، يكون مثيل الجزء
الذي قمت بإنشائه هو المثيل المستخدم. ومع ذلك، خلال
تغيير التهيئة، أو
إتلاف النشاط وجميع أجزائه ثم إعادة إنشائها مع
الأكثر قابلية للتطبيق
موارد Android
تعالج السمة FragmentManager
كل هذه الإجراءات نيابةً عنك، فهي تعيد إنشاء المثيلات
من الأجزاء، ثم يتم إرفاقها بالمضيف، ثم إعادة إنشاء الحزمة الخلفية
الولاية.
بشكل تلقائي، تستخدم السمة FragmentManager
FragmentFactory
الذي
يوفره إطار العمل لإنشاء مثيل جديد من الجزء. هذا النمط
يستخدم المصنع التلقائي الانعكاس للعثور على دالة إنشائية بدون وسيطة واستدعاءها
للجزء الخاص بك. وهذا يعني أنه لا يمكنك استخدام هذا المصنع الافتراضي
من التبعيات إلى الجزء الخاص بك. وهذا يعني أيضًا أن أي واجهة مخصصة
الدالة الإنشائية التي استخدمتها لإنشاء الجزء في المرة الأولى لا يتم استخدامها
أثناء إعادة الإنشاء تلقائيًا.
لتوفير الموارد التابعة للجزء الخاص بك، أو لاستخدام أي رموز
الدالة الإنشائية، فبدلاً من ذلك، أنشئ فئة فرعية مخصّصة من نوع FragmentFactory
ثم إلغاء
FragmentFactory.instantiate
يمكنك بعد ذلك إلغاء الإعدادات الأصلية التلقائية لجهاز FragmentManager
باستخدام
المصنع المخصص، الذي يتم استخدامه لإنشاء مثيل للأجزاء.
لنفترض أن لديك DessertsFragment
مسؤولة عن عرض
الحلويات الرائجة في بلدتك DessertsFragment
تعتمد على فئة DessertsRepository
توفر لها
المعلومات التي يحتاجها لعرض واجهة المستخدم الصحيحة للمستخدم.
يمكنك تحديد DessertsFragment
لطلب DessertsRepository
.
في الدالة الإنشائية.
Kotlin
class DessertsFragment(val dessertsRepository: DessertsRepository) : Fragment() { ... }
Java
public class DessertsFragment extends Fragment { private DessertsRepository dessertsRepository; public DessertsFragment(DessertsRepository dessertsRepository) { super(); this.dessertsRepository = dessertsRepository; } // Getter omitted. ... }
قد يبدو تنفيذ بسيط لـ FragmentFactory
مشابهًا لما يلي:
ما يلي.
Kotlin
class MyFragmentFactory(val repository: DessertsRepository) : FragmentFactory() { override fun instantiate(classLoader: ClassLoader, className: String): Fragment = when (loadFragmentClass(classLoader, className)) { DessertsFragment::class.java -> DessertsFragment(repository) else -> super.instantiate(classLoader, className) } }
Java
public class MyFragmentFactory extends FragmentFactory { private DessertsRepository repository; public MyFragmentFactory(DessertsRepository repository) { super(); this.repository = repository; } @NonNull @Override public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) { Class<? extends Fragment> fragmentClass = loadFragmentClass(classLoader, className); if (fragmentClass == DessertsFragment.class) { return new DessertsFragment(repository); } else { return super.instantiate(classLoader, className); } } }
ينطبق هذا المثال على الفئات الفرعية FragmentFactory
، ما يلغي instantiate()
.
لتوفير منطق إنشاء جزء مخصّص لـ DessertsFragment
.
ويتم التعامل مع فئات الأجزاء الأخرى من خلال السلوك الافتراضي
من FragmentFactory
إلى super.instantiate()
.
يمكنك بعد ذلك ضبط "MyFragmentFactory
" كمصنِّع لاستخدامه في حال.
إنشاء أجزاء التطبيق عن طريق ضبط خاصية على
FragmentManager
يجب إعداد هذه السمة قبل إعدادات نشاطك
super.onCreate()
لضمان استخدام MyFragmentFactory
عند
إعادة إنشاء أجزائك.
Kotlin
class MealActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { supportFragmentManager.fragmentFactory = MyFragmentFactory(DessertsRepository.getInstance()) super.onCreate(savedInstanceState) } }
Java
public class MealActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { DessertsRepository repository = DessertsRepository.getInstance(); getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory(repository)); super.onCreate(savedInstanceState); } }
يؤدي ضبط FragmentFactory
في النشاط إلى إلغاء الجزء.
الإنشاء عبر التسلسل الهرمي للأجزاء للنشاط. أو بعبارةٍ أخرى،
إنّ childFragmentManager
لأي أجزاء فرعية تضيفها يستخدم السمة المخصصة.
تم ضبط إعدادات المصنع في هذا الحقل ما لم يتم إلغاؤه على مستوى أقل.
الاختبار باستخدام Fragmentfactor
في بنية نشاط واحد، اختبر أجزائك في
بالعزل باستخدام
FragmentScenario
الصف. بما أنّه لا يمكنك الاعتماد على منطق onCreate
المخصّص
نشاط، يمكنك بدلاً من ذلك تمرير FragmentFactory
كوسيطة
في اختبار الأجزاء، كما هو موضح في المثال التالي:
// Inside your test val dessertRepository = mock(DessertsRepository::class.java) launchFragment<DessertsFragment>(factory = MyFragmentFactory(dessertRepository)).onFragment { // Test Fragment logic }
للحصول على معلومات تفصيلية حول عملية الاختبار هذه وأمثلة كاملة، راجِع اختبار الأجزاء.