নেভিগেশন উপাদানের সাথে প্রোগ্রাম্যাটিকভাবে ইন্টারঅ্যাক্ট করুন

ন্যাভিগেশন উপাদান নির্দিষ্ট নেভিগেশন উপাদানগুলির সাথে প্রোগ্রাম্যাটিকভাবে তৈরি এবং ইন্টারঅ্যাক্ট করার উপায় সরবরাহ করে।

একটি NavHostFragment তৈরি করুন

আপনি NavHostFragment.create() ব্যবহার করতে পারেন একটি নির্দিষ্ট গ্রাফ রিসোর্স দিয়ে একটি NavHostFragment তৈরি করতে, যেমনটি নীচের উদাহরণে দেখানো হয়েছে:

কোটলিন

val finalHost = NavHostFragment.create(R.navigation.example_graph)
supportFragmentManager.beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true"
    .commit()

জাভা

NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true"
    .commit();

মনে রাখবেন যে setPrimaryNavigationFragment(finalHost) আপনার NavHost সিস্টেমকে ব্যাক বোতাম টিপতে দেয়। আপনি app:defaultNavHost="true" যোগ করে আপনার NavHost XML-এ এই আচরণটি বাস্তবায়ন করতে পারেন। আপনি যদি কাস্টম ব্যাক বোতাম আচরণ বাস্তবায়ন করেন এবং আপনার NavHost ব্যাক বোতাম টিপে বাধা দিতে না চান, তাহলে আপনি setPrimaryNavigationFragment()null পাস করতে পারেন।

নেভিগেশন 2.2.0 দিয়ে শুরু করে, আপনি NavController.getBackStackEntry() এ কল করে, একটি গন্তব্য আইডি পাস করে নেভিগেশন স্ট্যাকের যেকোনো গন্তব্যের জন্য NavBackStackEntry এর একটি রেফারেন্স পেতে পারেন। যদি ব্যাক স্ট্যাকে নির্দিষ্ট গন্তব্যের একাধিক উদাহরণ থাকে, getBackStackEntry() স্ট্যাক থেকে সর্বোচ্চ উদাহরণ প্রদান করে।

ফিরে আসা NavBackStackEntry গন্তব্য স্তরে একটি Lifecycle , একটি ViewModelStore , এবং একটি SavedStateRegistry প্রদান করে৷ এই বস্তুগুলি পিছনের স্ট্যাকের গন্তব্যের আজীবনের জন্য বৈধ। যখন সংশ্লিষ্ট গন্তব্যটি ব্যাক স্ট্যাকের থেকে পপ করা হয়, তখন Lifecycle ধ্বংস হয়ে যায়, অবস্থা আর সংরক্ষিত হয় না এবং যেকোন ViewModel অবজেক্ট সাফ করা হয়।

এই বৈশিষ্ট্যগুলি আপনাকে একটি Lifecycle এবং ViewModel অবজেক্ট এবং ক্লাসগুলির জন্য একটি স্টোর দেয় যা আপনি যে ধরনের গন্তব্য ব্যবহার করেন না কেন সেভ করা অবস্থায় কাজ করে৷ এটি বিশেষভাবে উপযোগী যখন গন্তব্যের ধরনগুলির সাথে কাজ করে যেখানে স্বয়ংক্রিয়ভাবে কোন Lifecycle নেই, যেমন কাস্টম গন্তব্য।

উদাহরণস্বরূপ, আপনি একটি NavBackStackEntry এর Lifecycle পর্যবেক্ষণ করতে পারেন ঠিক যেমন আপনি একটি খণ্ড বা কার্যকলাপের Lifecycle পর্যবেক্ষণ করেন। উপরন্তু, NavBackStackEntry হল একটি LifecycleOwner , যার মানে হল আপনি LiveData পর্যবেক্ষণ করার সময় বা অন্যান্য জীবনচক্র-সচেতন উপাদানগুলির সাথে এটি ব্যবহার করতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

myViewModel.liveData.observe(backStackEntry, Observer { myData ->
    // react to live data update
})

জাভা

myViewModel.getLiveData().observe(backStackEntry, myData -> {
    // react to live data update
});

যখনই আপনি navigate() কল করেন তখনই লাইফসাইকেল অবস্থা স্বয়ংক্রিয়ভাবে আপডেট হয়। লাইফসাইকেল সেই গন্তব্যগুলির জন্য যেগুলি ব্যাক স্ট্যাকের শীর্ষে নেই সেগুলিকে RESUMED থেকে STARTED এ সরানো হয় যদি একটি FloatingWindow গন্তব্যের অধীনে গন্তব্যগুলি এখনও দৃশ্যমান হয়, যেমন একটি ডায়ালগ গন্তব্য বা অন্যথায় STOPPED এ।

পূর্ববর্তী গন্তব্যে একটি ফলাফল প্রত্যাবর্তন

নেভিগেশন 2.3 এবং উচ্চতর, NavBackStackEntry একটি SavedStateHandle এ অ্যাক্সেস দেয়। একটি SavedStateHandle হল একটি মূল-মান মানচিত্র যা ডেটা সংরক্ষণ এবং পুনরুদ্ধার করতে ব্যবহার করা যেতে পারে। এই মানগুলি কনফিগারেশন পরিবর্তন সহ প্রক্রিয়া মৃত্যুর মাধ্যমে অব্যাহত থাকে এবং একই বস্তুর মাধ্যমে উপলব্ধ থাকে। প্রদত্ত SavedStateHandle ব্যবহার করে, আপনি গন্তব্যগুলির মধ্যে ডেটা অ্যাক্সেস করতে এবং পাস করতে পারেন৷ এটি স্ট্যাক থেকে পপ অফ হওয়ার পরে একটি গন্তব্য থেকে ডেটা ফিরে পাওয়ার প্রক্রিয়া হিসাবে এটি বিশেষভাবে কার্যকর।

গন্তব্য B থেকে গন্তব্য A-তে ডেটা ফেরত পাঠাতে, SavedStateHandle এ ফলাফল শোনার জন্য প্রথমে গন্তব্য A সেট আপ করুন। এটি করতে, getCurrentBackStackEntry() API ব্যবহার করে NavBackStackEntry পুনরুদ্ধার করুন এবং তারপর SavedStateHandle দ্বারা প্রদত্ত LiveData observe

কোটলিন

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val navController = findNavController();
    // We use a String here, but any type that can be put in a Bundle is supported
    navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(
        viewLifecycleOwner) { result ->
        // Do something with the result.
    }
}

জাভা

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    NavController navController = NavHostFragment.findNavController(this);
    // We use a String here, but any type that can be put in a Bundle is supported
    MutableLiveData<String> liveData = navController.getCurrentBackStackEntry()
            .getSavedStateHandle()
            .getLiveData("key");
    liveData.observe(getViewLifecycleOwner(), new Observer<String>() {
        @Override
        public void onChanged(String s) {
            // Do something with the result.
        }
    });
}

গন্তব্য বি-তে, আপনাকে অবশ্যই getPreviousBackStackEntry() API ব্যবহার করে গন্তব্য A-এর SavedStateHandle এ ফলাফল set হবে।

কোটলিন

navController.previousBackStackEntry?.savedStateHandle?.set("key", result)

জাভা

navController.getPreviousBackStackEntry().getSavedStateHandle().set("key", result);

আপনি যদি শুধুমাত্র একবার একটি ফলাফল পরিচালনা করতে চান, তাহলে ফলাফলটি সাফ করতে আপনাকে অবশ্যই SavedStateHandleremove() কল করতে হবে। আপনি ফলাফলটি না সরিয়ে ফেললে, LiveData কোনো নতুন Observer দৃষ্টান্তে শেষ ফলাফল ফিরিয়ে দিতে থাকবে।

ডায়ালগ গন্তব্য ব্যবহার করার সময় বিবেচনা

যখন আপনি একটি গন্তব্যে navigate যেটি NavHost এর সম্পূর্ণ ভিউ নেয় (যেমন একটি <fragment> গন্তব্য), পূর্ববর্তী গন্তব্যটির জীবনচক্র বন্ধ হয়ে যায়, SavedStateHandle দ্বারা প্রদত্ত LiveData এ কোনো কলব্যাক প্রতিরোধ করে।

যাইহোক, একটি ডায়ালগ গন্তব্যে নেভিগেট করার সময়, পূর্ববর্তী গন্তব্যটিও স্ক্রিনে দৃশ্যমান হয় এবং তাই বর্তমান গন্তব্য না হওয়া সত্ত্বেও এটিও STARTED হয়৷ এর মানে হল যে onViewCreated() এর মতো জীবনচক্র পদ্ধতির মধ্যে থেকে getCurrentBackStackEntry() এ করা কলগুলি কনফিগারেশন পরিবর্তন বা মৃত্যু এবং বিনোদন প্রক্রিয়া করার পরে ডায়ালগ গন্তব্যের NavBackStackEntry ফিরিয়ে দেবে (যেহেতু ডায়ালগটি অন্য গন্তব্যের উপরে পুনরুদ্ধার করা হয়েছে)। তাই আপনি সর্বদা সঠিক NavBackStackEntry ব্যবহার করছেন তা নিশ্চিত করতে আপনার গন্তব্যের আইডি সহ getBackStackEntry() ব্যবহার করা উচিত।

এর মানে হল যে কোনও Observer যা আপনি ফলাফল LiveData সেট করেছেন তা ট্রিগার হবে এমনকি যখন ডায়ালগ গন্তব্যগুলি এখনও স্ক্রিনে থাকবে। আপনি যদি ডায়ালগ গন্তব্যটি বন্ধ হয়ে গেলে এবং অন্তর্নিহিত গন্তব্যটি বর্তমান গন্তব্যে পরিণত হলে শুধুমাত্র ফলাফলটি পরীক্ষা করতে চান, তাহলে আপনি NavBackStackEntry এর সাথে যুক্ত Lifecycle পর্যবেক্ষণ করতে পারেন এবং ফলাফলটি পুনরুদ্ধার করতে পারেন যখন এটি RESUMED হয়।

কোটলিন

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val navController = findNavController();
    // After a configuration change or process death, the currentBackStackEntry
    // points to the dialog destination, so you must use getBackStackEntry()
    // with the specific ID of your destination to ensure we always
    // get the right NavBackStackEntry
    val navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment)

    // Create our observer and add it to the NavBackStackEntry's lifecycle
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains("key")) {
            val result = navBackStackEntry.savedStateHandle.get<String>("key");
            // Do something with the result
        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })
}

জাভা

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    NavController navController = NavHostFragment.findNavController(this);
    // After a configuration change or process death, the currentBackStackEntry
    // points to the dialog destination, so you must use getBackStackEntry()
    // with the specific ID of your destination to ensure we always
    // get the right NavBackStackEntry
    final NavBackStackEntry navBackStackEntry = navController.getBackStackEntry(R.id.your_fragment);

    // Create our observer and add it to the NavBackStackEntry's lifecycle
    final LifecycleEventObserver observer = new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
            if (event.equals(Lifecycle.Event.ON_RESUME)
                && navBackStackEntry.getSavedStateHandle().contains("key")) {
                String result = navBackStackEntry.getSavedStateHandle().get("key");
                // Do something with the result
            }
        }
    };
    navBackStackEntry.getLifecycle().addObserver(observer);

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    getViewLifecycleOwner().getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
            if (event.equals(Lifecycle.Event.ON_DESTROY)) {
                navBackStackEntry.getLifecycle().removeObserver(observer)
            }
        }
    });
}

নেভিগেশন ব্যাক স্ট্যাক একটি NavBackStackEntry সঞ্চয় করে শুধুমাত্র প্রতিটি স্বতন্ত্র গন্তব্যের জন্যই নয়, প্রতিটি প্যারেন্ট নেভিগেশন গ্রাফের জন্যও যেটিতে পৃথক গন্তব্য রয়েছে। এটি আপনাকে একটি NavBackStackEntry পুনরুদ্ধার করতে দেয় যা একটি নেভিগেশন গ্রাফে স্কোপ করা হয়। একটি নেভিগেশন গ্রাফ-স্কোপড NavBackStackEntry একটি ViewModel তৈরি করার একটি উপায় প্রদান করে যা একটি নেভিগেশন গ্রাফে স্কোপ করা হয়েছে, যা আপনাকে গ্রাফের গন্তব্যগুলির মধ্যে UI- সম্পর্কিত ডেটা ভাগ করতে সক্ষম করে৷ এইভাবে তৈরি যেকোন ViewModel অবজেক্ট লাইভ থাকে যতক্ষণ না সংশ্লিষ্ট NavHost এবং এর ViewModelStore সাফ না হয় বা নেভিগেশন গ্রাফটি ব্যাক স্ট্যাক থেকে পপ না করা পর্যন্ত।

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে একটি ViewModel পুনরুদ্ধার করা যায় যা একটি নেভিগেশন গ্রাফে স্কোপ করা হয়েছে:

কোটলিন

val viewModel: MyViewModel
        by navGraphViewModels(R.id.my_graph)

জাভা

NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);
MyViewModel viewModel = new ViewModelProvider(backStackEntry).get(MyViewModel.class);

আপনি যদি নেভিগেশন 2.2.0 বা তার আগে ব্যবহার করে থাকেন, তাহলে আপনাকে ViewModels এর সাথে সেভড স্টেট ব্যবহার করার জন্য আপনার নিজস্ব ফ্যাক্টরি প্রদান করতে হবে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কোটলিন

val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph) {
    SavedStateViewModelFactory(requireActivity().application, requireParentFragment())
}

জাভা

NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

ViewModelProvider viewModelProvider = new ViewModelProvider(
        backStackEntry.getViewModelStore(),
        new SavedStateViewModelFactory(
                requireActivity().getApplication(), requireParentFragment()));

MyViewModel myViewModel = provider.get(myViewModel.getClass());

ViewModel সম্পর্কে আরও তথ্যের জন্য, ViewModel ওভারভিউ দেখুন।

স্ফীত ন্যাভিগেশন গ্রাফ পরিবর্তন করা হচ্ছে

আপনি রানটাইমে গতিশীলভাবে একটি স্ফীত নেভিগেশন গ্রাফ পরিবর্তন করতে পারেন।

উদাহরণ হিসেবে, আপনার যদি একটি BottomNavigationView থাকে যা একটি NavGraph এর সাথে আবদ্ধ থাকে, NavGraph এর ডিফল্ট গন্তব্য অ্যাপ স্টার্টআপে নির্বাচিত ট্যাবকে নির্দেশ করে। যাইহোক, আপনাকে এই আচরণটি ওভাররাইড করতে হতে পারে, যেমন যখন কোনও ব্যবহারকারীর পছন্দ অ্যাপ স্টার্টআপে লোড করার জন্য একটি পছন্দের ট্যাব নির্দিষ্ট করে। বিকল্পভাবে, ব্যবহারকারীর অতীতের আচরণের উপর ভিত্তি করে আপনার অ্যাপটিকে প্রারম্ভিক ট্যাব পরিবর্তন করতে হতে পারে। আপনি গতিশীলভাবে NavGraph এর ডিফল্ট গন্তব্য নির্দিষ্ট করে এই ক্ষেত্রে সমর্থন করতে পারেন।

এই NavGraph বিবেচনা করুন:

<?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">
    <fragment
        android:id="@+id/home"
        android:name="com.example.android.navigation.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home" />
    <fragment
        android:id="@+id/location"
        android:name="com.example.android.navigation.LocationFragment"
        android:label="fragment_location"
        tools:layout="@layout/fragment_location" />
    <fragment
        android:id="@+id/shop"
        android:name="com.example.android.navigation.ShopFragment"
        android:label="fragment_shop"
        tools:layout="@layout/fragment_shop" />
    <fragment
        android:id="@+id/settings"
        android:name="com.example.android.navigation.SettingsFragment"
        android:label="fragment_settings"
        tools:layout="@layout/fragment_settings" />
</navigation>

যখন এই গ্রাফটি লোড করা হয়, app:startDestination অ্যাট্রিবিউটটি নির্দিষ্ট করে যে HomeFragment প্রদর্শিত হবে। গতিশীলভাবে শুরুর গন্তব্য ওভাররাইড করতে, নিম্নলিখিতগুলি করুন:

  1. প্রথমে, ম্যানুয়ালি NavGraph ফুলিয়ে নিন।
  2. শুরুর গন্তব্য ওভাররাইড করুন।
  3. অবশেষে, ম্যানুয়ালি গ্রাফটিকে NavController সাথে সংযুক্ত করুন।

কোটলিন

val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment

val navController = navHostFragment.navController
val navGraph = navController.navInflater.inflate(R.navigation.bottom_nav_graph)
navGraph.startDestination = R.id.shop
navController.graph = navGraph
binding.bottomNavView.setupWithNavController(navController)

জাভা

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
        .findFragmentById(R.id.nav_host_fragment);

NavController navController = navHostFragment.getNavController();
NavGraph navGraph = navController.getNavInflater().inflate(R.navigation.bottom_nav_graph);
navGraph.setStartDestination(R.id.shop);
navController.setGraph(navGraph);
NavigationUI.setupWithNavController(binding.bottomNavView, navController);

এখন আপনার অ্যাপ শুরু হলে, HomeFragment এর পরিবর্তে ShopFragment দেখানো হয়।

গভীর লিঙ্কগুলি ব্যবহার করার সময়, NavController গভীর লিঙ্কের গন্তব্যের জন্য স্বয়ংক্রিয়ভাবে একটি ব্যাক স্ট্যাক তৈরি করে। ব্যবহারকারী যদি গভীর লিঙ্কে নেভিগেট করে এবং তারপরে পিছনের দিকে নেভিগেট করে, তবে তারা কোনও সময়ে শুরুর গন্তব্যে পৌঁছে যাবে। পূর্ববর্তী উদাহরণে কৌশলটি ব্যবহার করে শুরুর গন্তব্যকে ওভাররাইড করা নিশ্চিত করে যে সঠিক সূচনা গন্তব্যটি নির্মিত ব্যাক স্ট্যাকে যোগ করা হয়েছে।

মনে রাখবেন যে এই কৌশলটি প্রয়োজন অনুসারে NavGraph এর অন্যান্য দিকগুলিকে ওভাররাইড করার অনুমতি দেয়। গভীর লিঙ্কগুলি পরিচালনা করার সময়, অবস্থা পুনরুদ্ধার করার সময় এবং আপনার গ্রাফের শুরুর গন্তব্যে যাওয়ার সময় সঠিক কাঠামোটি ব্যবহার করা হয়েছে তা নিশ্চিত করার জন্য গ্রাফের সমস্ত পরিবর্তন অবশ্যই setGraph() এ কল করার আগে করা উচিত।