Issue
I am working on app have login, register and reset password screens, the problems is after register or logging in when I click on back button it dosen't close the app, it's navigate up to the register or logging screen even though I using app:launchSingleTop="true"
and app:popUpToInclusive="true"
but it seems doesn't work
The gif below explain the problem more
navigation graph 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())
);
}
MainActivity class
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: I tried the app without this method onSupportNavigateUp
but it doesn't effect, I also have another project with same structure but in kotlin and the everything working fine
Solution
After too many searches, I fixed it by app:popUpTo="@id/nav_graph"
so the action be like this
<action
android:id="@+id/action_loginFragment_to_homeFragment"
app:destination="@id/homeFragment"
app:launchSingleTop="true"
app:popUpTo="@id/nav_graph"
app:popUpToInclusive="true" />
Answered By - Dr Mido