বৈশিষ্ট্য মডিউল দিয়ে নেভিগেট করুন

ডায়নামিক ন্যাভিগেটর লাইব্রেরি জেটপ্যাক নেভিগেশন উপাদানটির কার্যকারিতা প্রসারিত করে যাতে ফিচার মডিউলে সংজ্ঞায়িত গন্তব্যগুলির সাথে কাজ করা যায়। এই গন্তব্যগুলিতে নেভিগেট করার সময় এই লাইব্রেরিটি অন-ডিমান্ড বৈশিষ্ট্য মডিউলগুলির বিরামহীন ইনস্টলেশন সরবরাহ করে।

সেটআপ

বৈশিষ্ট্য মডিউল সমর্থন করতে, আপনার অ্যাপ মডিউলের build.gradle ফাইলে নিম্নলিখিত নির্ভরতা ব্যবহার করুন:

গ্রোভি

dependencies {
    def nav_version = "2.7.7"

    api "androidx.navigation:navigation-fragment-ktx:$nav_version"
    api "androidx.navigation:navigation-ui-ktx:$nav_version"
    api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
}

কোটলিন

dependencies {
    val nav_version = "2.7.7"

    api("androidx.navigation:navigation-fragment-ktx:$nav_version")
    api("androidx.navigation:navigation-ui-ktx:$nav_version")
    api("androidx.navigation:navigation-dynamic-features-fragment:$nav_version")
}

নোট করুন যে অন্যান্য নেভিগেশন নির্ভরতাগুলি এপিআই কনফিগারেশন ব্যবহার করা উচিত যাতে সেগুলি আপনার বৈশিষ্ট্য মডিউলগুলিতে উপলব্ধ থাকে।

মৌলিক ব্যবহার

বৈশিষ্ট্য মডিউল সমর্থন করতে, প্রথমে আপনার অ্যাপে NavHostFragment এর সমস্ত উদাহরণ androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment এ পরিবর্তন করুন:

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host_fragment"
    android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
    app:navGraph="@navigation/nav_graph"
    ... />

এরপরে, একটি DynamicNavHostFragment এর সাথে যুক্ত আপনার com.android.dynamic-feature মডিউলের নেভিগেশন গ্রাফে যেকোনো <activity> , <fragment> , অথবা <navigation> গন্তব্যে একটি app:moduleName অ্যাট্রিবিউট যোগ করুন। এই বৈশিষ্ট্যটি ডায়নামিক নেভিগেটর লাইব্রেরীকে বলে যে গন্তব্যটি আপনার নির্দিষ্ট করা নামের একটি বৈশিষ্ট্য মডিউলের অন্তর্গত।

<fragment
    app:moduleName="myDynamicFeature"
    android:id="@+id/featureFragment"
    android:name="com.google.android.samples.feature.FeatureFragment"
    ... />

আপনি যখন এই গন্তব্যগুলির মধ্যে একটিতে নেভিগেট করেন, তখন ডায়নামিক নেভিগেটর লাইব্রেরি প্রথমে পরীক্ষা করে যে বৈশিষ্ট্য মডিউলটি ইনস্টল করা আছে কিনা। যদি বৈশিষ্ট্য মডিউলটি ইতিমধ্যেই উপস্থিত থাকে তবে আপনার অ্যাপটি প্রত্যাশা অনুযায়ী গন্তব্যে নেভিগেট করে। মডিউলটি উপস্থিত না থাকলে, আপনার অ্যাপটি একটি মধ্যবর্তী অগ্রগতি খণ্ড গন্তব্য দেখায় কারণ এটি মডিউলটি ইনস্টল করে। অগ্রগতি খণ্ডের ডিফল্ট বাস্তবায়ন একটি অগ্রগতি দণ্ড সহ একটি মৌলিক UI দেখায় এবং যেকোনো ইনস্টলেশন ত্রুটি পরিচালনা করে।

দুটি লোডিং স্ক্রিন যা প্রথমবার একটি বৈশিষ্ট্য মডিউলে নেভিগেট করার সময় একটি অগ্রগতি দণ্ড সহ UI দেখায়
চিত্র 1. যখন একজন ব্যবহারকারী প্রথমবারের জন্য একটি অন-ডিমান্ড বৈশিষ্ট্যে নেভিগেট করে তখন UI একটি অগ্রগতি বার দেখায়। অ্যাপটি এই স্ক্রীনটিকে সংশ্লিষ্ট মডিউল ডাউনলোড হিসাবে প্রদর্শন করে।

এই UI কাস্টমাইজ করতে, অথবা আপনার নিজের অ্যাপ স্ক্রীন থেকে ইনস্টলেশনের অগ্রগতি ম্যানুয়ালি পরিচালনা করতে, অগ্রগতি খণ্ডটি কাস্টমাইজ করুন এবং এই বিষয়ে অনুরোধের অবস্থার বিভাগগুলি পর্যবেক্ষণ করুন

যে গন্তব্যগুলি app:moduleName নির্দিষ্ট করে না সেগুলি পরিবর্তন ছাড়াই কাজ করতে থাকে এবং এমন আচরণ করে যেন আপনার অ্যাপ একটি নিয়মিত NavHostFragment ব্যবহার করে৷

অগ্রগতি খণ্ডটি কাস্টমাইজ করুন

আপনি ইনস্টলেশনের অগ্রগতি পরিচালনার জন্য যে গন্তব্যের আইডি ব্যবহার করতে চান সেটিতে app:progressDestination অ্যাট্রিবিউট সেট করে প্রতিটি নেভিগেশন গ্রাফের জন্য অগ্রগতি খণ্ড বাস্তবায়ন ওভাররাইড করতে পারেন। আপনার কাস্টম অগ্রগতি গন্তব্য হওয়া উচিত একটি Fragment যা AbstractProgressFragment থেকে এসেছে। ইনস্টলেশনের অগ্রগতি, ত্রুটি এবং অন্যান্য ইভেন্ট সম্পর্কে বিজ্ঞপ্তিগুলির জন্য আপনাকে অবশ্যই বিমূর্ত পদ্ধতিগুলিকে ওভাররাইড করতে হবে। তারপরে আপনি আপনার পছন্দের একটি UI এ ইনস্টলেশনের অগ্রগতি দেখাতে পারেন।

ডিফল্ট বাস্তবায়নের DefaultProgressFragment ক্লাস ইনস্টলেশনের অগ্রগতি দেখানোর জন্য এই API ব্যবহার করে।

অনুরোধ রাষ্ট্র নিরীক্ষণ

ডাইনামিক নেভিগেটর লাইব্রেরি আপনাকে অন-ডিমান্ড ডেলিভারির জন্য UX সর্বোত্তম অনুশীলনের অনুরূপ একটি UX ফ্লো বাস্তবায়ন করতে সক্ষম করে, যেখানে একজন ব্যবহারকারী ইনস্টলেশন শেষ হওয়ার জন্য অপেক্ষা করার সময় পূর্ববর্তী স্ক্রিনের প্রসঙ্গে থাকে। এর মানে হল যে আপনাকে কোনও মধ্যবর্তী UI বা অগ্রগতি খণ্ড দেখাতে হবে না।

স্ক্রীন যা একটি আইকন সহ একটি নীচের নেভি বার দেখায় যা নির্দেশ করে যে একটি বৈশিষ্ট্য মডিউল ডাউনলোড হচ্ছে
চিত্র 2. স্ক্রীন যা নিচের নেভিগেশন বার থেকে ডাউনলোডের অগ্রগতি দেখায়।

এই পরিস্থিতিতে, আপনি সমস্ত ইনস্টলেশন অবস্থা, অগ্রগতি পরিবর্তন, ত্রুটি, ইত্যাদি পর্যবেক্ষণ এবং পরিচালনার জন্য দায়ী।

এই নন-ব্লকিং নেভিগেশন ফ্লো শুরু করতে, একটি DynamicExtras অবজেক্ট পাস করুন যাতে একটি DynamicInstallMonitor আছে NavController.navigate() এ, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

val navController = ...
val installMonitor = DynamicInstallMonitor()

navController.navigate(
    destinationId,
    null,
    null,
    DynamicExtras(installMonitor)
)

জাভা

NavController navController = ...
DynamicInstallMonitor installMonitor = new DynamicInstallMonitor();

navController.navigate(
    destinationId,
    null,
    null,
    new DynamicExtras(installMonitor);
)

navigate() কল করার সাথে সাথেই, আপনাকে installMonitor.isInstallRequired এর মান পরীক্ষা করে দেখতে হবে যে নেভিগেশনের প্রচেষ্টার ফলে একটি বৈশিষ্ট্য মডিউল ইনস্টলেশন হয়েছে কিনা।

  • মানটি false হলে, আপনি একটি স্বাভাবিক গন্তব্যে নেভিগেট করছেন এবং অন্য কিছু করার দরকার নেই৷
  • মানটি true হলে, আপনার LiveData অবজেক্টটি পর্যবেক্ষণ করা শুরু করা উচিত যা এখন installMonitor.status এ রয়েছে। এই LiveData অবজেক্ট প্লে কোর লাইব্রেরি থেকে SplitInstallSessionState আপডেট নির্গত করে। এই আপডেটগুলিতে ইনস্টলেশনের অগ্রগতি ইভেন্ট রয়েছে যা আপনি UI আপডেট করতে ব্যবহার করতে পারেন। প্রয়োজনে ব্যবহারকারীর নিশ্চিতকরণের জন্য জিজ্ঞাসা সহ প্লে কোর গাইডে বর্ণিত সমস্ত প্রাসঙ্গিক স্থিতিগুলি পরিচালনা করতে মনে রাখবেন।

    কোটলিন

    val navController = ...
    val installMonitor = DynamicInstallMonitor()
    
    navController.navigate(
      destinationId,
      null,
      null,
      DynamicExtras(installMonitor)
    )
    
    if (installMonitor.isInstallRequired) {
      installMonitor.status.observe(this, object : Observer<SplitInstallSessionState> {
          override fun onChanged(sessionState: SplitInstallSessionState) {
              when (sessionState.status()) {
                  SplitInstallSessionStatus.INSTALLED -> {
                      // Call navigate again here or after user taps again in the UI:
                      // navController.navigate(destinationId, destinationArgs, null, null)
                  }
                  SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> {
                      SplitInstallManager.startConfirmationDialogForResult(...)
                  }
    
                  // Handle all remaining states:
                  SplitInstallSessionStatus.FAILED -> {}
                  SplitInstallSessionStatus.CANCELED -> {}
              }
    
              if (sessionState.hasTerminalStatus()) {
                  installMonitor.status.removeObserver(this);
              }
          }
      });
    }
    

    জাভা

    NavController navController = ...
    DynamicInstallMonitor installMonitor = new DynamicInstallMonitor();
    
    navController.navigate(
      destinationId,
      null,
      null,
      new DynamicExtras(installMonitor);
    )
    
    if (installMonitor.isInstallRequired()) {
      installMonitor.getStatus().observe(this, new Observer<SplitInstallSessionState>() {
          @Override
          public void onChanged(SplitInstallSessionState sessionState) {
              switch (sessionState.status()) {
                  case SplitInstallSessionStatus.INSTALLED:
                      // Call navigate again here or after user taps again in the UI:
                      // navController.navigate(mDestinationId, mDestinationArgs, null, null);
                      break;
                  case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION:
                      SplitInstallManager.startConfirmationDialogForResult(...)
                      break;
    
                  // Handle all remaining states:
                  case SplitInstallSessionStatus.FAILED:
                      break;
                  case SplitInstallSessionStatus.CANCELED:
                      break;
              }
    
              if (sessionState.hasTerminalStatus()) {
                  installMonitor.getStatus().removeObserver(this);
              }
          }
      });
    }
    

ইনস্টলেশন শেষ হলে, LiveData অবজেক্ট একটি SplitInstallSessionStatus.INSTALLED অবস্থা নির্গত করে। তারপরে আপনাকে আবার NavController.navigate() কল করতে হবে। যেহেতু মডিউলটি এখন ইনস্টল করা হয়েছে, কলটি এখন সফল হয়েছে, এবং অ্যাপটি প্রত্যাশা অনুযায়ী গন্তব্যে নেভিগেট করে।

একটি টার্মিনাল অবস্থায় পৌঁছানোর পরে, যেমন ইনস্টলেশন সম্পূর্ণ হলে বা ইনস্টলেশন ব্যর্থ হলে, মেমরি লিক এড়াতে আপনার LiveData পর্যবেক্ষককে সরিয়ে দেওয়া উচিত। আপনি SplitInstallSessionStatus.hasTerminalStatus() ব্যবহার করে স্ট্যাটাসটি একটি টার্মিনাল অবস্থার প্রতিনিধিত্ব করে কিনা তা পরীক্ষা করতে পারেন।

এই পর্যবেক্ষকের একটি উদাহরণ বাস্তবায়নের জন্য AbstractProgressFragment দেখুন।

গ্রাফ অন্তর্ভুক্ত

ডায়নামিক নেভিগেটর লাইব্রেরি ফিচার মডিউলে সংজ্ঞায়িত গ্রাফ সহ সমর্থন করে। একটি বৈশিষ্ট্য মডিউলে সংজ্ঞায়িত একটি গ্রাফ অন্তর্ভুক্ত করতে, নিম্নলিখিতগুলি করুন:

  1. <include <include/> এর পরিবর্তে <include-dynamic/> ব্যবহার করুন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

    <include-dynamic
        android:id="@+id/includedGraph"
        app:moduleName="includedgraphfeature"
        app:graphResName="included_feature_nav"
        app:graphPackage="com.google.android.samples.dynamic_navigator.included_graph_feature" />
    
  2. <include-dynamic ... /> এর ভিতরে, আপনাকে অবশ্যই নিম্নলিখিত বৈশিষ্ট্যগুলি নির্দিষ্ট করতে হবে:

    • app:graphResName : নেভিগেশন গ্রাফ রিসোর্স ফাইলের নাম। নামটি গ্রাফের ফাইলের নাম থেকে নেওয়া হয়েছে। উদাহরণস্বরূপ, যদি গ্রাফটি res/navigation/nav_graph.xml এ থাকে, তাহলে রিসোর্সের নাম হল nav_graph
    • android:id - গ্রাফ গন্তব্য আইডি। ডায়নামিক নেভিগেটর লাইব্রেরি অন্তর্ভুক্ত গ্রাফের মূল উপাদানে পাওয়া যেকোন android:id মানকে উপেক্ষা করে।
    • app:moduleName : মডিউলটির প্যাকেজ নাম।

সঠিক গ্রাফপ্যাকেজ ব্যবহার করুন

app:graphPackage সঠিক কারণ ন্যাভিগেশন উপাদানটি বৈশিষ্ট্য মডিউল থেকে নির্দিষ্ট navGraph অন্তর্ভুক্ত করতে সক্ষম হবে না, অন্যথায়।

একটি ডাইনামিক ফিচার মডিউলের প্যাকেজ নামটি বেস অ্যাপ মডিউলের applicationId মডিউলের নাম যুক্ত করে তৈরি করা হয়। তাই যদি বেস অ্যাপ মডিউলে com.example.dynamicfeatureapp এর একটি applicationId থাকে এবং ডায়নামিক ফিচার মডিউলটির নাম হয় DynamicFeatureModule , তাহলে ডায়নামিক মডিউলটির প্যাকেজের নাম হবে com.example.dynamicfeatureapp.DynamicFeatureModule । এই প্যাকেজের নাম কেস-সংবেদনশীল।

আপনার যদি কোনো সন্দেহ থাকে, তাহলে আপনি জেনারেট করা AndroidManifest.xml চেক করে ফিচার মডিউলের প্যাকেজের নাম নিশ্চিত করতে পারেন। প্রকল্পটি তৈরি করার পরে <DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml এ যান, যা দেখতে এইরকম কিছু হওয়া উচিত:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:dist="http://schemas.android.com/apk/distribution"
    featureSplit="DynamicFeatureModule"
    package="com.example.dynamicfeatureapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="30" />

    <dist:module
        dist:instant="false"
        dist:title="@string/title_dynamicfeaturemodule" >
        <dist:delivery>
            <dist:install-time />
        </dist:delivery>

        <dist:fusing dist:include="true" />
    </dist:module>

    <application />

</manifest>

featureSplit মানটি ডায়নামিক ফিচার মডিউলের নামের সাথে মেলে এবং প্যাকেজটি বেস অ্যাপ মডিউলের applicationId সাথে মিলবে। app:graphPackage হল এইগুলির সংমিশ্রণ: com.example.dynamicfeatureapp.DynamicFeatureModule

একটি include-dynamic নেভিগেশন গ্রাফের startDestination নেভিগেট করা শুধুমাত্র সম্ভব। ডায়নামিক মডিউলটি তার নিজস্ব নেভিগেশন গ্রাফের জন্য দায়ী এবং বেস অ্যাপের সে সম্পর্কে কোন জ্ঞান নেই।

অন্তর্ভুক্ত-ডাইনামিক মেকানিজম বেস অ্যাপ মডিউলকে একটি নেস্টেড নেভিগেশন গ্রাফ অন্তর্ভুক্ত করতে সক্ষম করে যা ডাইনামিক মডিউলের মধ্যে সংজ্ঞায়িত করা হয়। এই নেস্টেড নেভিগেশন গ্রাফ যেকোনো নেস্টেড নেভিগেশন গ্রাফের মতো আচরণ করে। রুট নেভিগেশন গ্রাফ (অর্থাৎ, নেস্টেড গ্রাফের অভিভাবক) শুধুমাত্র নেস্টেড নেভিগেশন গ্রাফটিকেই একটি গন্তব্য হিসেবে সংজ্ঞায়িত করতে পারে এবং এর সন্তানদের নয়। সুতরাং, যখন অন্তর্ভুক্ত-গতিশীল নেভিগেশন গ্রাফ গন্তব্য হয় তখন startDestination ব্যবহার করা হয়।

সীমাবদ্ধতা

  • গতিশীল-অন্তর্ভুক্ত গ্রাফ বর্তমানে গভীর লিঙ্ক সমর্থন করে না।
  • গতিশীলভাবে লোড করা নেস্টেড গ্রাফ (অর্থাৎ, একটি app:moduleName সহ একটি <navigation> উপাদান) বর্তমানে গভীর লিঙ্কগুলিকে সমর্থন করে না।