(Android, java) Cannot rename a child node twice in Firebase realtime database (已解决:阅读我第一个 post 的底部以获得答案)

(Android, java) Cannot rename a child node twice in Firebase realtime database (Solved: Read the bottom of my first post for answer)

我有一个按钮可以重命名 firebase 数据库中的子节点,还有一个 editTextView 供用户输入新子节点名称的字符串。在按下按钮时,字符串将从 editTextView 中提取并用于重命名子节点。

在我将子节点从用户名 "Paul" 重命名为用户名 "John" 的编码方法中,我会:(1) 创建一个名为 "John" 的新子节点,以及 (2 ) 将"Paul"子节点中的值复制到"John"子节点,最后(3)删除"Paul"子节点。

我编写的代码可以毫无问题地成功重命名为用户名 "John",但是当我想第二次重命名为名为 "Ken" 的新用户名时,按下按钮第二次,整个节点将被彻底清除,意味着什么都没有留下。为什么 "Ken" 子节点不见了,我该如何修复代码?


这里是数据库控制台的屏幕截图,解释了单击按钮时发生的情况。

(图1)这是点击按钮前的状态。初始用户名是 "Paul":

(图2)这是第一次按下按钮重命名为"John"。代码功能到目前为止没有错误:

(图3)这是第二次按下按钮重命名为"Ken"。这些代码没有按预期运行,不幸的是删除了所有节点并且 "Ken" 不会出现。


这是我编写的代码片段: 作为记录,字符串变量 "username" 是现有用户名(这里是 "Paul"),字符串变量 "temporaryUsername" 是新名称(这里是 "John" - 按下按钮,第二次按下按钮时应该是 "Ken")。 "usernameInputView" 的 editTextView 是从中提取字符串变量 "temporaryUsername" 的地方。

usernameSharedPreferences = getSharedPreferences("usernameSharedPreferences", Context.MODE_PRIVATE);
        username = usernameSharedPreferences.getString("userName", "");



renameUserButton.setOnClickListener(new View.OnClickListener() {
                if (username!=null && !username.equals("")) {    //Check that the existing username isn't empty

                        String temporaryUsername = usernameInputView.getText().toString();

                        if (temporaryUsername!=null && !temporaryUsername.equals("")) {

                            // (1) Creatw a new child node (temporaryUsername)
                            mRootReference.child("Users' Input History").child(temporaryUsername).push().setValue("");

                            // (2) Copy the values from the exisiting node (username) to the new node (temporaryUsername)
                            DatabaseReference usersInputHistorySourceNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(username);
                            final DatabaseReference usersInputHistoryTargetNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(temporaryUsername);
                            ValueEventListener valueEventListenerForUsersInputHistory = new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {
                                    usersInputHistoryTargetNode.setValue(dataSnapshot.getValue()).addOnCompleteListener(new OnCompleteListener<Void>() {
                                        @Override
                                        public void onComplete(@NonNull Task<Void> task) {
                                            if (task.isComplete()) {
                                                Log.d("User Input History copy", "Success!");
                                            } else {
                                                Log.d("User Input History copy", "Copy failed!");
                                            }
                                        }
                                    });
                                }

                                @Override
                                public void onCancelled(@NonNull DatabaseError databaseError) {}
                            };
                            usersInputHistorySourceNode.addListenerForSingleValueEvent(valueEventListenerForUsersInputHistory);


                           // (3) Remove the existing node (username)
                            mChildReferenceForInputHistory.child(username).removeValue();

                            //Make "username" equal to "temporaryUsername" (meaning to make "temporaryUsername" as the new existing username) and save into SharedPreferences
                        usernameSharedPreferences = getSharedPreferences("usernameSharedPreferences", MODE_PRIVATE);
                        usernameSharedPreferences.edit().putString("userName", temporaryUsername).apply();


                            Toast.makeText(getApplicationContext(), getResources().getString(R.string.Your_new_username_is) + temporaryUsername, Toast.LENGTH_LONG).show();
                        }

                        else {
                            Toast.makeText(getApplicationContext(), R.string.You_have_not_entered_any_username, Toast.LENGTH_LONG).show();
                        }
                    }

                    else {
                        Toast.makeText(getApplicationContext(), R.string.You_have_not_entered_any_username, Toast.LENGTH_LONG).show();
                    }
            });

这是我尝试过的方法:

我试图强制 运行 重命名过程两次。我将 OnClickListener 中的整个代码打包到一个名为 renameNode() 的辅助方法中,并连续两次将 renameNode() 传递给 OnClickListener。我想,如果第二次不成功,那么我可以强制它在第 3 次再次 运行 重命名过程,但我仍然没有成功。使用此方法,数据库中甚至不会出现单个节点(与上图3中的情况相同),所以我现在没有技巧了。以下是准确的代码:

    String temporaryUsername;

renameUserButton.setOnClickListener(new View.OnClickListener() {
                if (username!=null && !username.equals("")) {    //Check that the existing username isn't empty

                        temporaryUsername = usernameInputView.getText().toString();

                        renameNode();
                        renameNode();
                        }

                        else {
                            Toast.makeText(getApplicationContext(), R.string.You_have_not_entered_any_username, Toast.LENGTH_LONG).show();
                        }
                    }

                    else {
                        Toast.makeText(getApplicationContext(), R.string.You_have_not_entered_any_username, Toast.LENGTH_LONG).show();
                    }
            });



    public void renameNode() {

                        if (temporaryUsername!=null && !temporaryUsername.equals("")) {

                            // (1) Creatw a new child node (temporaryUsername)
                            mRootReference.child("Users' Input History").child(temporaryUsername).push().setValue("");

                            // (2) Copy the values from the exisiting node (username) to the new node (temporaryUsername)
                            DatabaseReference usersInputHistorySourceNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(username);
                            final DatabaseReference usersInputHistoryTargetNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(temporaryUsername);
                            ValueEventListener valueEventListenerForUsersInputHistory = new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {
                                    usersInputHistoryTargetNode.setValue(dataSnapshot.getValue()).addOnCompleteListener(new OnCompleteListener<Void>() {
                                        @Override
                                        public void onComplete(@NonNull Task<Void> task) {
                                            if (task.isComplete()) {
                                                Log.d("User Input History copy", "Success!");
                                            } else {
                                                Log.d("User Input History copy", "Copy failed!");
                                            }
                                        }
                                    });
                                }

                                @Override
                                public void onCancelled(@NonNull DatabaseError databaseError) {}
                            };
                            usersInputHistorySourceNode.addListenerForSingleValueEvent(valueEventListenerForUsersInputHistory);


                           // (3) Remove the existing node (username)
                            mChildReferenceForInputHistory.child(username).removeValue();

                            //Make "username" equal to "temporaryUsername" (meaning to make "temporaryUsername" as the new existing username) and save into SharedPreferences
                        usernameSharedPreferences = getSharedPreferences("usernameSharedPreferences", MODE_PRIVATE);
                        usernameSharedPreferences.edit().putString("userName", temporaryUsername).apply();


                            Toast.makeText(getApplicationContext(), getResources().getString(R.string.Your_new_username_is) + temporaryUsername, Toast.LENGTH_LONG).show();
}

(ANSWER) 这个问题在 Khagan Azizov 的帮助下解决了。

我把 "mChildReferenceForInputHistory.child(username).removeValue()" 放错了位置,应该把它移到 "Log.d("User Input History copy", "Success!")".

上面一行

所以这是更正后的代码块:

DatabaseReference usersInputHistorySourceNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(username);
                        final DatabaseReference usersInputHistoryTargetNode = FirebaseDatabase.getInstance().getReference().child("Users' Input History").child(temporaryUsername);
                        ValueEventListener valueEventListenerForUsersInputHistory = new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                usersInputHistoryTargetNode.setValue(dataSnapshot.getValue()).addOnCompleteListener(new OnCompleteListener<Void>() {
                                    @Override
                                    public void onComplete(@NonNull Task<Void> task) {
                                        if (task.isComplete()) {
                                            **// (3) Remove the existing node (username)
                                            mChildReferenceForInputHistory.child(username).removeValue();**
                                            Log.d("User Input History copy", "Success!");
                                        } else {
                                            Log.d("User Input History copy", "Copy failed!");
                                        }
                                    }
                                });
                            }

                            @Override
                            public void onCancelled(@NonNull DatabaseError databaseError) {}
                        };
                        usersInputHistorySourceNode.addListenerForSingleValueEvent(valueEventListenerForUsersInputHistory);

此外,我还要感谢 GrahamD 为我指明了避免损坏数据的正确方向。

您是否在第一次按下按钮后更改了用户名变量中的数据?