我正在编写一个程序的静态方法,我一直在努力浏览Firebase数据库中“灰名单”中的条目,并检查用户输入以查看该条目是否存在。我能够很好地找到该条目,但由于线程在从/向Firebase读取/写入数据时的工作方式受到一些限制,我无法弄清楚如何通知用户操作是否成功或不
我有以下方法:
public static void addUser() {
final boolean [] complete = new boolean[1];
final String email = Tools.getEmail();
DatabaseReference grayRef = FirebaseDatabase.getInstance().getReference().child("graylist");
// Search the graylist for the email specified.
CountDownLatch latch = new CountDownLatch(1); // need this so Parse-Ly doesn't close before event fires
grayRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onCancelled(DatabaseError dbe) {}
@Override
public void onDataChange(DataSnapshot snap) {
Iterable<DataSnapshot> graylist = snap.getChildren();
for(DataSnapshot gray : graylist) {
String uid = gray.getKey();
String em = gray.getValue(String.class);
if(em.equals(email)) {
// We found the one we're looking for. Insert its UID into the whitelist.
DatabaseReference whiteRef = FirebaseDatabase.getInstance().getReference().child("whitelist");
whiteRef.child(uid).setValue(email, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError dbe, DatabaseReference dbr) {
complete[0] = true;
latch.countDown();
if(dbe != null) {
System.err.println("Error adding user to whitelist!");
dbe.toException().printStackTrace();
}
}
});
break;
}
}
if(latch.getCount() > 0) {
complete[0] = false;
latch.countDown();
}
}
});
try {
latch.await(); // wait for event to fire before we move on
} catch(InterruptedException ie) {
System.err.println("ERROR: Add user latch interrupted!");
ie.printStackTrace();
}
if(complete[0]) ParselyMain.createAlert(AlertType.CONFIRMATION, "User Added", "User added to the whitelist!");
else ParselyMain.createAlert(AlertType.INFORMATION, "User Not Found", "That user was not found in the graylist!");
}
我意识到最终的布尔数组是多么hacky,但即使这样也不适合我。我们的想法是使用CountDownLatch,只有在写入成功时才倒计时。如果读取了灰名单中的所有条目并且CountDownLatch仍为1,则没有写入任何内容,并且它应该倒计时退出线程,但布尔值将确定操作是否成功。
问题是,在调用onComplete方法之前,它似乎在我的for循环之后到达if块,导致它认为操作失败(即使Firebase上的数据库显示其他情况),并输出错误的警报。
任何人都可以想出一个更好的方法来处理这个问题,以便我可以正确地告知他们用户是否已添加到白名单中,或者是否找不到用户?
答案 0 :(得分:0)
Firebase数据库上的操作本质上是异步的,所以即使你以某种方式使上述代码工作,最终你会遇到更复杂的情况,其中大部分代码行正在进行同步而不是处理功能你的申请。这将导致难以维护的代码容易破解。
所以最简单的&#34;自然&#34;处理数据库请求的方法是在代码发生时处理代码中的每个事件。这意味着在调用onComplete
方法时通知用户成功更新,并在检查完所有子实体且未找到匹配项时通知用户失败:
public static void addUser() {
final String email = Tools.getEmail();
DatabaseReference grayRef = FirebaseDatabase.getInstance().getReference().child("graylist");
// Search the graylist for the email specified.
grayRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onCancelled(DatabaseError dbe) {}
@Override
public void onDataChange(DataSnapshot snap) {
boolean found = false;
Iterable<DataSnapshot> graylist = snap.getChildren();
for(DataSnapshot gray : graylist) {
String uid = gray.getKey();
String em = gray.getValue(String.class);
if(em.equals(email)) {
found = true;
// We found the one we're looking for. Insert its UID into the whitelist.
DatabaseReference whiteRef = FirebaseDatabase.getInstance().getReference().child("whitelist");
whiteRef.child(uid).setValue(email, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError dbe, DatabaseReference dbr) {
complete[0] = true;
if(dbe != null) {
System.err.println("Error adding user to whitelist!");
dbe.toException().printStackTrace();
} else {
Platform.runLater(() -> {
ParselyMain.createAlert(AlertType.CONFIRMATION, "User Added", "User added to the whitelist!");
});
}
}
});
break;
}
}
if(!found) {
Platform.runLater(() -> {
ParselyMain.createAlert(AlertType.INFORMATION, "User Not Found", "That user was not found in the graylist!");
});
}
}
});
}
答案 1 :(得分:0)
我没有足够的声誉,因此我无法直接在您的问题中发表评论。对不起。
Firebase实际上有自己的主题。在调用if
后,Firebase会打开一个新线程(或者只使用其已经存在的独立线程),因此您的原始线程会立即继续到public class FirebaseHandler {
// parameters
private DatabaseReference databaseReference;
// constructor
public FirebaseHandler() {
// you'll most probably need these for some actions
databaseReference = FirebaseDatabase.getInstance().getReference();
}
// interface
public interface FirebaseInterface {
void firebaseComplete(String serverStatus, String email);
}
// listener
private FirebaseInterface listener;
// set listener
public void setListener(FirebaseInterface listener) {
this.listener = listener;
}
/* getter for references, these will be useful to avoid calling the wrong place */
// -- /
public DatabaseReference getRoot() {
return databaseReference;
}
// -- /email /* specify the data structure here */
public DatabaseReference getEmailRef() {
return getRoot().child("email");
}
// finally your method
public static void addUser() {
// your codes here...
whiteRef.child(uid).setValue(email, new DatabaseReference.CompletionListener() {
@Override
public void onComplete(DatabaseError dbe, DatabaseReference dbr) {
// some action here....
if (listener != null) listener.firebaseComplete("OK", email);
}
});
}
}
块,因为它认为要完成操作,这就是你看到了结果。
因此,您需要的实际上是一个监听器,一旦Firebase完成其操作,它将与您的主要活动进行通信。既然你说你没有使用android,你可以创建一个特定的类来处理Firebase,它还包括接口和监听器。例如,
class Main implements FirebaseHandler.FirebaseInterface {
FirebaseHandler firebaseHandler = new FirebaseHandler();
firebaseHandler.setListener(this);
firebaseHandler.addUser();
@Override
public void firebaseComplete(String serverStatus, String email) {
firebaseHandler.setListener(null); // optional to remove listener
if (serverStatus.equals("OK") {
ParselyMain.createAlert(AlertType.CONFIRMATION, "User Added", "User added to the whitelist!");
} else {
ParselyMain.createAlert(AlertType.INFORMATION, "User Not Found", "That user was not found in the graylist!");
}
}
}
您只需在活动中附加侦听器并实现其方法即可。所以在你的UI线程......
UPDATE o
SET sku = p.AutoSKU
FROM o (NOLOCK)
JOIN a (NOLOCK) ON a.Sku = o.sku
JOIN p (NOLOCK) ON p.Code = a.ProductCode
WHERE o.sku <> p.AutoSKU
AND sku = a.Sku