Koşullu gezinme

Uygulamanız için gezinmeyi tasarlarken en az koşullu mantığa göre bir diğerini seçin. Örneğin, Kullanıcının giriş yapmasını gerektiren bir hedefe giden derin bağlantıyı izleyebilir ya da oyuncunun ne zaman oynayacağı oyunda farklı veya kayba uğrayabilir.

Kullanıcı girişi

Bu örnekte, bir kullanıcı kimlik doğrulama. Bu işlem kimlik doğrulama gerektirdiğinden, kullanıcı kimliği doğrulanmamışsa bir giriş ekranına yönlendirilir.

Bu örnek için gezinme grafiği şöyle görünebilir:

bir giriş akışı, uygulamanın ana
            gezinme akışını takip eder.
Şekil 1. Giriş akışı, ana gezinme akışını izleyin.

Kimlik doğrulaması için uygulamanın login_fragment konumuna gitmesi gerekir. Burada kullanıcı kimlik doğrulaması için bir kullanıcı adı ve şifre girebilir. Kabul edilirse kullanıcı profile_fragment ekranına geri gönderildi. Kabul edilmezse kullanıcı kimlik bilgilerinin geçersiz olduğunu bildirmek için bir Snackbar. Kullanıcı giriş yapmadan profil ekranına geri dönerse main_fragment ekranına gönderildi.

Aşağıda bu uygulamaya ilişkin gezinme grafiği verilmiştir:

<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, kullanıcının profilini görüntülemek için tıklayabileceği bir düğme içeriyor. Profil ekranını görmek isteyen kullanıcılar öncelikle kimliğini doğrulamalıdır. Bu etkileşim iki ayrı parça kullanılarak modellenir, ancak kullanıcı durumu. Bu eyalet bilgilerinin sorumluluğu, aşağıdakilerden herhangi birinin sorumluluğunda değildir daha uygun bir şekilde ortak bir UserViewModel içinde tutulmasını sağlar. Bu ViewModel, etkinlikle ilgili kapsamı belirlenerek parçalar arasında paylaşılır. ViewModelStoreOwner uygular. Aşağıdaki örnekte, requireActivity() ana makine MainActivity olduğundan MainActivity olarak çözümlenir 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 uygulamasındaki kullanıcı verileri LiveData üzerinden açığa çıkar. Bu verilere, nerede erişileceğine karar verilir. bu verileri gözlemlemeniz gerekir. Gittikten sonra ProfileFragment, kullanıcı verileri aşağıdaki gibiyse uygulama bir karşılama mesajı gösterir: devam eder. Kullanıcı verileri null ise LoginFragment bölümüne gidersiniz. çünkü kullanıcının profilini görebilmek için kimlik doğrulaması yapması gerekir. Tanımlayın aşağıdaki örnekte gösterildiği gibi ProfileFragment etiketinizde karar verme mantığı:

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 hedefine ulaştıklarında kullanıcı verileri null ise LoginFragment alanına yönlendirildi.

Tekliflerinizi otomatikleştirmek ve optimize etmek için NavController.getPreviousBackStackEntry() almak için NavBackStackEntry önceki hedefe ilişkin NavController'a özgü durumudur. LoginFragment, SavedStateHandle önceki NavBackStackEntry ile kullanıcı başarıyla giriş yaptı. Bu, eğer şu durumda geri dönmek isteyeceğimiz eyalettir: kullanıcının hemen sistem geri düğmesine basması gerekir. Bu durumu ayarlama SavedStateHandle kullanılması, durumun süreç ölümü boyunca devam etmesini sağlar.

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);
    }
}

Kullanıcı bir kullanıcı adı ve şifre girdikten sonra, Kimlik doğrulama için UserViewModel. Kimlik doğrulama başarılı olursa UserViewModel, kullanıcı verilerini depolar. Ardından LoginFragment, SavedStateHandle üzerinde LOGIN_SUCCESSFUL değeri var ve otomatik olarak ekrandan çıkıyor hazırlar.

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
    }
}

Kimlik doğrulamayla ilgili tüm mantığın UserViewModel Bu, kurumun sorumluluğunda olmadığı için önemlidir. belirlemek için LoginFragment veya ProfileFragment kimlik doğrulaması yapılmış. Mantığınızı bir ViewModel içine almak, test edilmesi de daha kolay olur. Gezinme mantığınız karmaşıksa bu mantığı özellikle test ederek doğrulamanız gerekir. Bkz. Daha fazla bilgi için uygulama mimarisi rehberi uygulamanızın mimarisini test edilebilir bileşenlere göre yapılandırma.

ProfileFragment içinde, LOGIN_SUCCESSFUL değeri SavedStateHandle, onCreate() yöntemidir. Kullanıcı ProfileFragment geri döndüğünde LOGIN_SUCCESSFUL kontrol edilir. Değer false ise kullanıcı geri yönlendirilebilir 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);
                    }
                });
    }

    ...
}

Kullanıcı başarıyla giriş yaparsa ProfileFragment, ekranda bir karşılama mesajı.

Burada sonucu kontrol etmek için kullanılan teknik, birbirinizle :

  • Kullanıcının giriş yapmadığı ve hesabının istenmesi gereken ilk durum giriş yapın.
  • Kullanıcı, giriş yapmamayı seçtiği için giriş yapmamıştır. ( false).

Bu kullanım alanlarını birbirinden ayırt ederek size sürekli olarak kullanıcının giriş yapmasını sağlar. Başarısız destek kayıtlarının ele alınması için iş mantığı size bağlıdır ve kullanıcının uygulamayı neden tekrar etmesi gerektiğini açıklayan bir yer paylaşımı görüntüleyebilir. Giriş yapma, tüm etkinliği tamamlama veya kullanıcıyı bir hedefe yönlendirme (ör. önceki kod örneğinde olduğu gibi) giriş gerektirmeyen yeni bir kod oluşturun.