أفضل ممارسات التنقّل للمشاريع المتعدّدة الوحدات

يمكن أن يتكون الرسم البياني للتنقل من أي مجموعة مما يلي:

  • تمثّل هذه السمة وجهة فردية، مثل وجهة <fragment>.
  • رسم بياني مدمج التي تضم مجموعة من الوجهات ذات الصلة.
  • أحد عناصر <include> الذي يسمح لك بتضمين ملف رسم بياني تنقل آخر كما لو كان متداخلة.

تتيح لك هذه المرونة دمج الرسوم البيانية الصغيرة للتنقل معًا تشكل رسمًا بيانيًا للتنقل كاملاً في تطبيقك، حتى إذا كانت عناصر التنقل الأصغر يتم تقديم الرسوم البيانية من خلال وحدات منفصلة.

بالنسبة للأمثلة في هذا الموضوع، كل يتم التركيز على وحدة الميزات حول ميزة واحدة رسمًا بيانيًا واحدًا للتنقُّل يتضمّن جميع الوجهات اللازمة لتنفيذ هذه الميزة. في تطبيق الإنتاج، قد يكون لديك العديد من وحدات فرعية على المستوى الأدنى تمثل تفاصيل تنفيذ هذا المستوى الأعلى الجديدة. يتم تضمين كل وحدة من وحدات الميزات هذه، إما بشكل مباشر بشكل غير مباشر في وحدة app. المثال يتضمّن التطبيق المتعدّد الوحدات المستخدَم في هذا المستند الهيكل التالي:

رسم بياني للتبعية لنموذج تطبيق متعدد الوحدات
وجهة بدء التطبيق كمثال
الشكل 1. بنية التطبيق ووجهة البدء للحصول على نموذج التطبيق

كل وحدة من وحدات الميزات هي وحدة مستقلة مع رسم بياني للتنقل والوجهات. وتعتمد وحدة app على كل وحدة، وتتم إضافتها في شكل تفاصيل التنفيذ في ملف build.gradle على النحو التالي:

Groovy

dependencies {
    ...
    implementation project(":feature:home")
    implementation project(":feature:favorites")
    implementation project(":feature:settings")

Kotlin

dependencies {
    ...
    implementation(project(":feature:home"))
    implementation(project(":feature:favorites"))
    implementation(project(":feature:settings"))

دور وحدة app

تعد وحدة app مسؤولة عن تقديم الرسم البياني الكامل التطبيق وإضافة NavHost إلى واجهة المستخدم. ضِمن الوحدات الخاصة بالوحدة app الرسم البياني للتنقل، يمكنك الرجوع إلى الرسوم البيانية للمكتبة باستخدام <include> بينما استخدام <include> هو في الوظيفة نفسها تمامًا مثل استخدام رسم بياني متداخل، تتيح ميزة <include> استخدام الرسوم البيانية من وحدات المشاريع الأخرى أو من المكتبة. للمشروعات، كما هو موضح في المثال التالي:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />
</navigation>

بعد تضمين مكتبة في الرسم البياني للتنقل في المستوى الأعلى، يمكنك التنقل إلى الرسوم البيانية للمكتبة حسب الحاجة. على سبيل المثال، يمكنك إنشاء إجراء للانتقال إلى الرسم البياني للإعدادات من أحد أجزاء الرسم البياني كما هو موضح:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/home_nav_graph">

    <include app:graph="@navigation/home_navigation" />
    <include app:graph="@navigation/favorites_navigation" />
    <include app:graph="@navigation/settings_navigation" />

    <fragment
        android:id="@+id/random_fragment"
        android:name="com.example.android.RandomFragment"
        android:label="@string/fragment_random" >
        <!-- Launch into Settings Navigation Graph -->
        <action
            android:id="@+id/action_random_fragment_to_settings_nav_graph"
            app:destination="@id/settings_nav_graph" />
    </fragment>
</navigation>

عندما تحتاج وحدات ميزات متعددة إلى الإشارة إلى مجموعة مشتركة من مثل الرسم البياني لتسجيل الدخول، ينبغي ألا تضمين تلك الوجهات المشتركة في مخطط التنقل في كل وحدة من وحدات الميزات. بدلاً من ذلك، إضافة هذه الوجهات الشائعة إلى الرسم البياني للتنقل في وحدة app. يمكن لكل وحدة ميزات الانتقال بين وحدات الميزات الانتقال إلى هذه الوجهات المشتركة

في المثال السابق، يحدد الإجراء وجهة تنقل من @id/settings_nav_graph. يشير هذا المعرّف إلى وجهة محددة في الرسم البياني المتضمن @navigation/settings_navigation.

التنقّل في المستوى الأعلى في وحدة التطبيق

يتضمن مكوِّن التنقل صف واحد (NavigationUI). تحتوي هذه الفئة على طرق ثابتة تدير التنقل باستخدام الجزء العلوي شريط التطبيقات ودرج التنقل والتنقل السفلي. إذا كان تطبيقك تتكون الوجهات ذات المستوى الأعلى من عناصر واجهة المستخدم التي توفرها الميزة وحدات app، فهي موضع طبيعي لوضع الصفحات ذات المستوى الأعلى وعناصر التنقل وواجهة المستخدم. ولأنّ وحدة التطبيق تعتمد على وحدات الميزات التعاونية، يمكن الوصول إلى جميع وجهاتها من الرمز البرمجي المحدّد في وحدة التطبيق هذا يعني أنه يمكنك استخدام من NavigationUI إلى ربط الوجهات بعناصر القائمة إذا كان معرّف السلعة يتطابق مع معرّف وجهة

في الشكل 2، يحدّد مثال الوحدة app BottomNavigationView في نشاطه الرئيسي. تتطابق أرقام تعريف عناصر القائمة في القائمة مع شريط التنقّل. معرفات الرسم البياني للرسومات البيانية للمكتبة:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@id/home_nav_graph"
        android:icon="@drawable/ic_home"
        android:title="Home"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/favorites_nav_graph"
        android:icon="@drawable/ic_favorite"
        android:title="Favorites"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@id/settings_nav_graph"
        android:icon="@drawable/ic_settings"
        android:title="Settings"
        app:showAsAction="ifRoom" />
</menu>

للسماح لـ NavigationUI بمعالجة التنقل السفلي، اتصال setupWithNavController() من onCreate() في صف النشاط الرئيسي، كما هو موضح في ما يلي مثال:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController

    findViewById<BottomNavigationView>(R.id.bottom_nav)
            .setupWithNavController(navController)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    NavHostFragment navHostFragment =
            (NavHostFragment) supportFragmentManager.findFragmentById(R.id.nav_host_fragment);
    NavController navController = navHostFragment.getNavController();
    BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);

    NavigationUI.setupWithNavController(bottomNav, navController);
}

عند استخدام هذا الرمز، ينتقل NavigationUI إلى القسم الرسم البياني للمكتبة عندما ينقر المستخدم على عنصر التنقل السفلي.

يُرجى ملاحظة أنّه من السيئ عمومًا أن تكون لديك وحدة تطبيقك الاعتمادية القوية على وجهة معينة مضمّنة بشكل عميق داخل وحدات الميزات الرسم البياني للتنقل. في معظم الحالات، تريد أن يتضمن تطبيقك للتعرف فقط على نقطة الدخول إلى أي وحدة الرسوم البيانية للتنقل (ينطبق هذا خارج وحدات الميزات أيضًا). إذا كنت بحاجة للربط بوجهة معيّنة في الرسم البياني للتنقل في مكتبتك، الطريقة المفضلة للقيام بذلك هي استخدام رابط لصفحة في التطبيق: الربط بصفحة معيّنة أيضًا الطريقة الوحيدة للمكتبة للانتقال إلى وجهة في وجهة أخرى الرسم البياني للتنقل في المكتبة.

التنقّل بين وحدات الميزات

في وقت التجميع، لا يمكن لوحدات الخصائص المستقلة التعرف على بعضها، لكي لا تتمكّن من استخدام أرقام التعريف للانتقال إلى وجهات في وحدات أخرى. بدلاً من ذلك، استخدام رابط لصفحة معيّنة للتنقل مباشرةً إلى وجهة مرتبطة رابط ضمني لصفحة في التطبيق:

استمرارًا للمثال السابق، تخيل أنك بحاجة إلى الانتقال من زر في وحدة :feature:home إلى وجهة مدمَجة في :feature:settings واحدة. يمكنك إجراء ذلك من خلال إضافة رابط لصفحة في التطبيق إلى الوجهة في الإعدادات. الرسم البياني للتنقل، كما هو موضح:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/settings_nav_graph"
    app:startDestination="@id/settings_fragment_one">

    ...

    <fragment
        android:id="@+id/settings_fragment_two"
        android:name="com.example.google.login.SettingsFragmentTwo"
        android:label="@string/settings_fragment_two" >

        <deepLink
            app:uri="android-app://example.google.app/settings_fragment_two" />
    </fragment>
</navigation>

بعد ذلك، أضِف الرمز التالي إلى onClickListener للزر في الصفحة الرئيسية. الجزء:

Kotlin

button.setOnClickListener {
    val request = NavDeepLinkRequest.Builder
        .fromUri("android-app://example.google.app/settings_fragment_two".toUri())
        .build()
    findNavController().navigate(request)
}

Java

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        NavDeepLinkRequest request = NavDeepLinkRequest.Builder
            .fromUri(Uri.parse("android-app://example.google.app/settings_fragment_two"))
            .build();
        NavHostFragment.findNavController(this).navigate(request);
    }
});

على عكس التنقّل باستخدام معرّفات الإجراءات أو الوجهات، يمكنك الانتقال إلى أي عنوان URI في أي رسم بياني، حتى عبر الوحدات.

عند استخدام معرّف الموارد المنتظم (URI)، لا تتم إعادة ضبط حزمة الرجوع. هذا السلوك هو على عكس التنقل عبر الروابط الصريحة لصفحات في التطبيق، حيث يتم استبدال الحزمة الخلفية عند التنقل.