(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 为我指明了避免损坏数据的正确方向。
您是否在第一次按下按钮后更改了用户名变量中的数据?
我有一个按钮可以重命名 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 为我指明了避免损坏数据的正确方向。
您是否在第一次按下按钮后更改了用户名变量中的数据?