阻止应用在向上导航时返回 login/register 屏幕

Prevent app from back to login/register screen on navigate up

我正在开发具有登录、注册和重设密码屏幕的应用程序,问题是在注册或登录后,当我单击后退按钮时它没有关闭应用程序,它向上导航到注册或登录屏幕尽管我使用 app:launchSingleTop="true"app:popUpToInclusive="true" 但它似乎不起作用


下面的动图更能说明问题

导航图xml

<?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/registerFragment">

    <fragment
        android:id="@+id/loginFragment"
        android:name="com.mml.mymall.LoginFragment"
        android:label="fragment_login"
        tools:layout="@layout/fragment_login">
        <action
            android:id="@+id/action_loginFragment_to_registerFragment"
            app:destination="@id/registerFragment"
            app:enterAnim="@anim/slide_in_left"
            app:exitAnim="@anim/slide_in_right"
            app:popEnterAnim="@anim/slide_out_right"
            app:popExitAnim="@anim/slide_out_left" />
        <action
            android:id="@+id/action_loginFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:launchSingleTop="true"
            app:popUpToInclusive="true" />
        <action
            android:id="@+id/action_loginFragment_to_resetPasswordFragment"
            app:destination="@id/resetPasswordFragment"
            app:popUpTo="@id/loginFragment" />
    </fragment>
    <fragment
        android:id="@+id/registerFragment"
        android:name="com.mml.mymall.RegisterFragment"
        android:label="fragment_register"
        tools:layout="@layout/fragment_register">
        <action
            android:id="@+id/action_registerFragment_to_loginFragment"
            app:destination="@id/loginFragment"
            app:enterAnim="@anim/slide_in_left"
            app:exitAnim="@anim/slide_out_right"
            app:popEnterAnim="@anim/slide_out_right"
            app:popExitAnim="@anim/slide_out_left" />
        <action
            android:id="@+id/action_registerFragment_to_homeFragment"
            app:destination="@id/homeFragment"
            app:launchSingleTop="false"
            app:popUpToInclusive="true" />
    </fragment>
    <fragment
        android:id="@+id/homeFragment"
        android:name="com.mml.mymall.HomeFragment"
        android:label="fragment_home"
        tools:layout="@layout/fragment_home"/>
    <fragment
        android:id="@+id/resetPasswordFragment"
        android:name="com.mml.mymall.ResetPasswordFragment"
        android:label="fragment_reset_password"
        tools:layout="@layout/fragment_reset_password" />
</navigation>

LoginFragment

public class LoginFragment extends Fragment {

    private FragmentLoginBinding binding;
    private FirebaseAuth firebaseAuth;


    @Override
    public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        binding = FragmentLoginBinding.inflate(inflater, container, false);
        firebaseAuth = FirebaseAuth.getInstance();
        return binding.getRoot();

    }

    @Override
    public void onViewCreated(@NonNull @NotNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.inputEmail.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                checkInputs();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

        binding.inputPassword.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                checkInputs();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

        binding.btnlogin.setOnClickListener(view1 -> checkEmailAndPassword());

        binding.textViewSignUp.setOnClickListener(view1 ->
                Navigation.findNavController(requireView()).navigate(
                        LoginFragmentDirections.actionLoginFragmentToRegisterFragment()
                )
        );

        binding.forgotPassword.setOnClickListener(view1 ->
                Navigation.findNavController(requireView()).navigate(LoginFragmentDirections.actionLoginFragmentToResetPasswordFragment()
        ));

    }



    private void checkEmailAndPassword() {
        binding.progressBar.setVisibility(View.VISIBLE);
        if (TextUtils.isEmpty(binding.inputEmail.getText()) ||
                !Patterns.EMAIL_ADDRESS.matcher(binding.inputEmail.getText()).matches()) {
            binding.inputEmail.setError("Invalid email");
            binding.progressBar.setVisibility(View.INVISIBLE);
        } else if (TextUtils.isEmpty(binding.inputPassword.getText()) ||
                binding.inputPassword.getText().toString().length() < 8) {
            binding.inputPassword.setError("Invalid password");
            binding.progressBar.setVisibility(View.INVISIBLE);
        } else {
            firebaseAuth.signInWithEmailAndPassword(binding.inputEmail.getText().toString(),
                    binding.inputPassword.getText().toString()).addOnCompleteListener(task -> {
                if (task.isSuccessful()) {
                    binding.progressBar.setVisibility(View.INVISIBLE);
                    Navigation.findNavController(requireView())
                            .navigate(LoginFragmentDirections
                                    .actionLoginFragmentToHomeFragment());
                } else {
                    binding.progressBar.setVisibility(View.INVISIBLE);
                    Toast.makeText(requireContext(), task.getException().getMessage(), Toast.LENGTH_LONG).show();
                }
            });
        }

    }


    private void checkInputs() {
        if (!TextUtils.isEmpty(binding.inputEmail.getText())) {
            binding.btnlogin.setEnabled(!TextUtils.isEmpty(binding.inputPassword.getText()));
        } else {
            binding.btnlogin.setEnabled(false);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

RegisterFragment

 @Override
    public void onViewCreated(@NonNull @NotNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.alreadyHaveAccount.setOnClickListener(view1 ->
                Navigation.findNavController(getView())
                        .navigate(RegisterFragmentDirections.actionRegisterFragmentToLoginFragment())
        );
}

MainActivityclass

public class MainActivity extends AppCompatActivity {

    private NavController navController;
    private FirebaseAuth firebaseAuth;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.Theme_MyMall);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        firebaseAuth = FirebaseAuth.getInstance();
        FirebaseUser currentUser = firebaseAuth.getCurrentUser();

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

        navController = navHostFragment.getNavController();

        if (currentUser != null) {
            navController.navigate(R.id.homeFragment);
        }

    }

    @Override
    public boolean onSupportNavigateUp() {
        return navController.navigateUp() || super.onSupportNavigateUp();
    }

}

PS: 我在没有这个方法的情况下尝试了应用程序 onSupportNavigateUp 但它没有效果,我还有另一个具有相同结构但在kotlin 和一切正常

您应该将 popUpTo 属性 设置为操作。由于您的起始目的地是 RegisterFragment,您可以将 popUpTo="@id/registerFragment" 设置为 @id/action_loginFragment_to_homeFragment@id/action_registerFragment_to_homeFragment

例如:

<action
    android:id="@+id/action_loginFragment_to_homeFragment"
    app:destination="@id/homeFragment"
    app:launchSingleTop="true"
    app:popUpTo="@id/registerFragment"
    app:popUpToInclusive="true" />

经过多次搜索,我通过app:popUpTo="@id/nav_graph"修复了它,所以操作是这样的

<action
android:id="@+id/action_loginFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true" />