Android开发:用户关闭App时删除Firebase未完成注册数据
Hey there, let's tackle this problem together! The issue you're facing is that onDestroyView() only triggers when the Fragment is explicitly destroyed (like navigating back), but not when the app is closed abruptly—since the system might kill the process without firing Fragment lifecycle methods. Here's how to fix this reliably:
1. Track if the username was successfully set
First, add a boolean flag to your AddUsername fragment to distinguish between completed and incomplete setup. This ensures we only clean up accounts where the user didn't finish setting a username:
private boolean isUsernameSet = false;
Update this flag to true once the user successfully saves their valid username (add this inside your username validation logic):
// Inside checkUsernameAlreadyExist, after confirming the username is available mDatabase.child("users").child(user.getUid()).child("username").setValue(getUsername) .addOnSuccessListener(aVoid -> { isUsernameSet = true; // Proceed to the next screen as usual fragmentComm.toSetName(); });
2. Use ProcessLifecycleOwner to detect app exit/background
To catch when the app is closed or sent to the background, we'll use Android's ProcessLifecycleOwner, which listens to the entire app's lifecycle (not just individual fragments/activities).
First, ensure you have the required dependency in your module-level build.gradle:
implementation "androidx.lifecycle:lifecycle-process:2.6.2"
Then, register a lifecycle observer in your AddUsername fragment:
private LifecycleObserver appLifecycleObserver; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); appLifecycleObserver = new DefaultLifecycleObserver() { @Override public void onStop(@NonNull LifecycleOwner owner) { super.onStop(owner); // Check if app is moving to background AND username wasn't set if (!isUsernameSet && !owner.getLifecycle().isCurrentStateAtLeast(Lifecycle.State.STARTED)) { cleanupIncompleteAccount(); } } }; ProcessLifecycleOwner.get().getLifecycle().addObserver(appLifecycleObserver); } // Centralized cleanup method to delete database entry and user account private void cleanupIncompleteAccount() { if (user == null) return; // First delete the database entry, then the user account mDatabase.child("users").child(user.getUid()).removeValue() .addOnSuccessListener(aVoid -> { user.delete().addOnCompleteListener(task -> { if (task.isSuccessful()) { Log.d(TAG, "Incomplete user account deleted successfully"); } else { Log.e(TAG, "Failed to delete user account", task.getException()); } }); }) .addOnFailureListener(e -> { Log.e(TAG, "Failed to delete database entry", e); // Even if database delete fails, try to remove the user account user.delete(); }); } @Override public void onDestroyView() { super.onDestroyView(); // Remove observer to avoid memory leaks ProcessLifecycleOwner.get().getLifecycle().removeObserver(appLifecycleObserver); // Handle back navigation case (redundant but adds safety) if (!isUsernameSet) { cleanupIncompleteAccount(); } }
3. Fix your original code's operation order
Your initial code called mAuth.signOut() before deleting the user, which is risky—once signed out, the user object may lose permission to call delete(). The cleanupIncompleteAccount method above fixes this by deleting the database entry first, then the user account. There's no need to sign out manually, since deleting the user automatically invalidates their session.
4. Explicitly handle back button (optional)
For more control over back navigation, use OnBackPressedCallback instead of relying on onDestroyView:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); requireActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { cleanupIncompleteAccount(); // Navigate back to SignUp fragment requireActivity().getSupportFragmentManager().popBackStack(); } }); // ... rest of your onViewCreated code }
This approach ensures that whether the user presses back or closes the app, incomplete accounts get cleaned up properly.
内容的提问来源于stack exchange,提问作者Kasian Blithe Caballero

