कंडिशनल नेविगेशन

अपने ऐप्लिकेशन के लिए नेविगेशन डिज़ाइन करते समय, आपके पास इनमें से किसी एक गंतव्य बनाम अन्य. उदाहरण के लिए, अगर किसी उपयोगकर्ता ने किसी ऐसे डेस्टिनेशन के डीप लिंक पर जा सकता है जिसके लिए उपयोगकर्ता को लॉग करना ज़रूरी है या गेम में अलग-अलग डेस्टिनेशन हो सकते हैं. जीत या हार मिली.

उपयोगकर्ता लॉगिन

इस उदाहरण में, कोई उपयोगकर्ता ऐसी प्रोफ़ाइल स्क्रीन पर जाने की कोशिश करता है जिसके लिए पुष्टि करने के लिए. इस कार्रवाई के लिए पुष्टि ज़रूरी है, इसलिए उपयोगकर्ता को यह करना चाहिए अगर उपयोगकर्ता की पुष्टि पहले से नहीं की गई है, तो उन्हें लॉगिन स्क्रीन पर रीडायरेक्ट कर दिया जाएगा.

इस उदाहरण के लिए नेविगेशन ग्राफ़ कुछ ऐसा दिख सकता है:

लॉगिन फ़्लो को ऐप्लिकेशन के मुख्य प्लैटफ़ॉर्म से अलग मैनेज किया जाता है
            नेविगेशन फ़्लो पर जाएं.
पहली इमेज. लॉगिन फ़्लो को ऐप्लिकेशन के मुख्य नेविगेशन फ़्लो का इस्तेमाल करता है.

पुष्टि करने के लिए, ऐप्लिकेशन को login_fragment पर जाना होगा, जहां उपयोगकर्ता प्रमाणित करने के लिए उपयोगकर्ता नाम और पासवर्ड डाल सकते हैं. इसे स्वीकार किए जाने पर, उपयोगकर्ता profile_fragment पर वापस भेजी गई. अगर इसे स्वीकार नहीं किया जाता है, तो उपयोगकर्ता यह सूचना दी गई है कि उनके क्रेडेंशियल अमान्य हैं. इसके लिए, Snackbar. अगर उपयोगकर्ता लॉग इन किए बिना प्रोफ़ाइल स्क्रीन पर वापस जाता है, तो उसे main_fragment की स्क्रीन पर भेजा गया.

यहां इस ऐप्लिकेशन का नेविगेशन ग्राफ़ दिया गया है:

<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/main_fragment">
    <fragment
            android:id="@+id/main_fragment"
            android:name="com.google.android.conditionalnav.MainFragment"
            android:label="fragment_main"
            tools:layout="@layout/fragment_main">
        <action
                android:id="@+id/navigate_to_profile_fragment"
                app:destination="@id/profile_fragment"/>
    </fragment>
    <fragment
            android:id="@+id/login_fragment"
            android:name="com.google.android.conditionalnav.LoginFragment"
            android:label="login_fragment"
            tools:layout="@layout/login_fragment"/>
    <fragment
            android:id="@+id/profile_fragment"
            android:name="com.google.android.conditionalnav.ProfileFragment"
            android:label="fragment_profile"
            tools:layout="@layout/fragment_profile"/>
</navigation>

MainFragment में एक बटन होता है, जिस पर क्लिक करके उपयोगकर्ता अपनी प्रोफ़ाइल देख सकते हैं. अगर उपयोगकर्ता प्रोफ़ाइल स्क्रीन देखना चाहता है, तो पहले उसे अपनी पहचान की पुष्टि करनी होगी. यह इंटरैक्शन को दो अलग-अलग फ़्रैगमेंट का इस्तेमाल करके मॉडल किया जाता है. हालांकि, यह शेयर किए गए उपयोगकर्ता की स्थिति. राज्य की यह जानकारी इनमें से किसी के लिए भी ज़िम्मेदार नहीं है ये दो फ़्रैगमेंट शेयर किए गए हैं. साथ ही, इन्हें शेयर किए गए UserViewModel में बेहतर तरीके से रखा गया है. इस ViewModel को गतिविधि से जोड़कर, फ़्रैगमेंट के बीच शेयर किया गया है, जो ViewModelStoreOwner को लागू करता है. नीचे दिए गए उदाहरण में, requireActivity(), MainActivity में बदल जाता है, क्योंकि MainActivity होस्ट ProfileFragment:

Kotlin

class ProfileFragment : Fragment() {
    private val userViewModel: UserViewModel by activityViewModels()
    ...
}

Java

public class ProfileFragment extends Fragment {
    private UserViewModel userViewModel;
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);
        ...
    }
    ...
}

UserViewModel में उपयोगकर्ता का डेटा, LiveData से बिना अनुमति के सार्वजनिक किया जाता है. इससे यह तय किया जा सकता है कि आपको इस डेटा पर नज़र रखनी होगी. नेविगेट करने पर ProfileFragment, अगर उपयोगकर्ता का डेटा उपस्थित. अगर उपयोगकर्ता का डेटा null है, तो LoginFragment पर जाएं, क्योंकि उपयोगकर्ता को अपनी प्रोफ़ाइल देखने से पहले खाते की पुष्टि करनी होगी. परिभाषित करें आपके ProfileFragment में लॉजिक, जैसा कि इस उदाहरण में दिखाया गया है:

Kotlin

class ProfileFragment : Fragment() {
    private val userViewModel: UserViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val navController = findNavController()
        userViewModel.user.observe(viewLifecycleOwner, Observer { user ->
            if (user != null) {
                showWelcomeMessage()
            } else {
                navController.navigate(R.id.login_fragment)
            }
        })
    }

    private fun showWelcomeMessage() {
        ...
    }
}

Java

public class ProfileFragment extends Fragment {
    private UserViewModel userViewModel;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);
        final NavController navController = Navigation.findNavController(view);
        userViewModel.user.observe(getViewLifecycleOwner(), (Observer<User>) user -> {
            if (user != null) {
                showWelcomeMessage();
            } else {
                navController.navigate(R.id.login_fragment);
            }
        });
    }

    private void showWelcomeMessage() {
        ...
    }
}

अगर उपयोगकर्ता का डेटा ProfileFragment तक पहुंचने के बाद null है, तो इसका मतलब है कि LoginFragment पर रीडायरेक्ट किया गया.

Google Analytics 4 पर माइग्रेट करने के लिए, NavController.getPreviousBackStackEntry() NavBackStackEntry को फिर से पाने के लिए पिछले गंतव्य के लिए, जो NavController-विशिष्ट गंतव्य की जानकारी दें. LoginFragment कुल SavedStateHandle पिछले NavBackStackEntry का इस्तेमाल करके शुरुआती वैल्यू सेट करें. इससे यह पता चलेगा कि उपयोगकर्ता ने सफलतापूर्वक लॉग इन कर लिया है. यह वह राज्य है जिसे हम तब वापस लौटाना चाहेंगे, जब उपयोगकर्ता को तुरंत सिस्टम के 'वापस जाएं' बटन को दबाना पड़ता था. इस स्थिति को सेट किया जा रहा है SavedStateHandle का इस्तेमाल करने से यह पक्का होता है कि प्रोसेस के बंद होने के बाद भी स्थिति बनी रहेगी.

Kotlin

class LoginFragment : Fragment() {
    companion object {
        const val LOGIN_SUCCESSFUL: String = "LOGIN_SUCCESSFUL"
    }

    private val userViewModel: UserViewModel by activityViewModels()
    private lateinit var savedStateHandle: SavedStateHandle

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        savedStateHandle = findNavController().previousBackStackEntry!!.savedStateHandle
        savedStateHandle.set(LOGIN_SUCCESSFUL, false)
    }
}

Java

public class LoginFragment extends Fragment {
    public static String LOGIN_SUCCESSFUL = "LOGIN_SUCCESSFUL"

    private UserViewModel userViewModel;
    private SavedStateHandle savedStateHandle;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);

        savedStateHandle = Navigation.findNavController(view)
                .getPreviousBackStackEntry()
                .getSavedStateHandle();
        savedStateHandle.set(LOGIN_SUCCESSFUL, false);
    }
}

उपयोगकर्ता नाम और पासवर्ड डालने के बाद, उसे पुष्टि करने के लिए UserViewModel. अगर पुष्टि सफल होती है, तो UserViewModel में उपयोगकर्ता का डेटा सेव होता है. इसके बाद, LoginFragment SavedStateHandle पर LOGIN_SUCCESSFUL मान और अपने आप बंद हो जाता है पिछली गतिविधियां.

Kotlin

class LoginFragment : Fragment() {
    companion object {
        const val LOGIN_SUCCESSFUL: String = "LOGIN_SUCCESSFUL"
    }

    private val userViewModel: UserViewModel by activityViewModels()
    private lateinit var savedStateHandle: SavedStateHandle

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        savedStateHandle = findNavController().previousBackStackEntry!!.savedStateHandle
        savedStateHandle.set(LOGIN_SUCCESSFUL, false)

        val usernameEditText = view.findViewById(R.id.username_edit_text)
        val passwordEditText = view.findViewById(R.id.password_edit_text)
        val loginButton = view.findViewById(R.id.login_button)

        loginButton.setOnClickListener {
            val username = usernameEditText.text.toString()
            val password = passwordEditText.text.toString()
            login(username, password)
        }
    }

    fun login(username: String, password: String) {
        userViewModel.login(username, password).observe(viewLifecycleOwner, Observer { result ->
            if (result.success) {
                savedStateHandle.set(LOGIN_SUCCESSFUL, true)
                findNavController().popBackStack()
            } else {
                showErrorMessage()
            }
        })
    }

    fun showErrorMessage() {
        // Display a snackbar error message
    }
}

Java

public class LoginFragment extends Fragment {
    public static String LOGIN_SUCCESSFUL = "LOGIN_SUCCESSFUL"

    private UserViewModel userViewModel;
    private SavedStateHandle savedStateHandle;

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        userViewModel = new ViewModelProvider(requireActivity()).get(UserViewModel.class);

        savedStateHandle = Navigation.findNavController(view)
                .getPreviousBackStackEntry()
                .getSavedStateHandle();
        savedStateHandle.set(LOGIN_SUCCESSFUL, false);

        EditText usernameEditText = view.findViewById(R.id.username_edit_text);
        EditText passwordEditText = view.findViewById(R.id.password_edit_text);
        Button loginButton = view.findViewById(R.id.login_button);

        loginButton.setOnClickListener(v -> {
            String username = usernameEditText.getText().toString();
            String password = passwordEditText.getText().toString();
            login(username, password);
        });
    }

    private void login(String username, String password) {
        userViewModel.login(username, password).observe(viewLifecycleOwner, (Observer<LoginResult>) result -> {
            if (result.success) {
                savedStateHandle.set(LOGIN_SUCCESSFUL, true);
                NavHostFragment.findNavController(this).popBackStack();
            } else {
                showErrorMessage();
            }
        });
    }

    private void showErrorMessage() {
        // Display a snackbar error message
    }
}

ध्यान दें कि पुष्टि करने से जुड़े सभी लॉजिक, UserViewModel. यह महत्वपूर्ण है, क्योंकि यह आपकी ज़िम्मेदारी नहीं है LoginFragment या ProfileFragment से यह पता लगाया जा सकता है कि उपयोगकर्ता कैसे हैं पुष्टि की गई है. अपने लॉजिक को ViewModel में एन्क्रिप्ट करने से, न सिर्फ़ शेयर करने में आसान लेकिन परीक्षण करने में भी आसान. अगर आपका नेविगेशन लॉजिक जटिल है, आपको खास तौर पर इस लॉजिक की पुष्टि टेस्ट के ज़रिए करनी चाहिए. ज़्यादा जानकारी के लिए, इनके बारे में ज़्यादा जानकारी के लिए, ऐप्लिकेशन के आर्किटेक्चर की गाइड टेस्ट किए जा सकने वाले कॉम्पोनेंट के आस-पास अपने ऐप्लिकेशन के आर्किटेक्चर को तैयार करना.

ProfileFragment में वापस, LOGIN_SUCCESSFUL मान SavedStateHandle को इसमें देखा जा सकता है: onCreate() तरीका. जब उपयोगकर्ता ProfileFragment पर वापस आता है, तो LOGIN_SUCCESSFUL मान की जांच की जाएगी. अगर वैल्यू false है, तो उपयोगकर्ता को वापस रीडायरेक्ट किया जा सकता है MainFragment तक.

Kotlin

class ProfileFragment : Fragment() {
    ...

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val navController = findNavController()

        val currentBackStackEntry = navController.currentBackStackEntry!!
        val savedStateHandle = currentBackStackEntry.savedStateHandle
        savedStateHandle.getLiveData<Boolean>(LoginFragment.LOGIN_SUCCESSFUL)
                .observe(currentBackStackEntry, Observer { success ->
                    if (!success) {
                        val startDestination = navController.graph.startDestination
                        val navOptions = NavOptions.Builder()
                                .setPopUpTo(startDestination, true)
                                .build()
                        navController.navigate(startDestination, null, navOptions)
                    }
                })
    }

    ...
}

Java

public class ProfileFragment extends Fragment {
    ...

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        NavController navController = NavHostFragment.findNavController(this);

        NavBackStackEntry navBackStackEntry = navController.getCurrentBackStackEntry();
        SavedStateHandle savedStateHandle = navBackStackEntry.getSavedStateHandle();
        savedStateHandle.getLiveData(LoginFragment.LOGIN_SUCCESSFUL)
                .observe(navBackStackEntry, (Observer<Boolean>) success -> {
                    if (!success) {
                        int startDestination = navController.getGraph().getStartDestination();
                        NavOptions navOptions = new NavOptions.Builder()
                                .setPopUpTo(startDestination, true)
                                .build();
                        navController.navigate(startDestination, null, navOptions);
                    }
                });
    }

    ...
}

अगर उपयोगकर्ता ने सही तरीके से लॉग इन कर लिया है, तो ProfileFragment वेलकम मैसेज.

नतीजे की जांच करने के लिए, यहां इस्तेमाल की गई तकनीक का इस्तेमाल करके, अंतर करने के लिए यह तरीका अपनाया जा सकता है दो भिन्न मामलों के बीच में:

  • शुरुआती स्थिति, जहां उपयोगकर्ता ने लॉग इन नहीं किया है और उसे ऐसा करने के लिए कहा जाना चाहिए लॉगिन करें.
  • उपयोगकर्ता ने लॉग इन नहीं किया है, क्योंकि उन्होंने लॉग इन न करने का विकल्प चुना (इसकी वजह से false).

इस्तेमाल के इन उदाहरणों में अंतर करके, उपयोगकर्ताओं से बार-बार उपयोगकर्ता लॉगिन करें. गड़बड़ी के मामलों को मैनेज करने के लिए, कारोबारी नियम आपके हिसाब से तय किए जाते हैं और इसमें ऐसा ओवरले दिखाया जा सकता है जो बताता हो कि उपयोगकर्ता को लॉगिन करना, पूरी गतिविधि को पूरा करना या उपयोगकर्ता को किसी डेस्टिनेशन पर रीडायरेक्ट करना के लिए लॉगिन की आवश्यकता नहीं होती, जैसा कि पिछले कोड उदाहरण में किया गया था.