2017-04-11 2 views
3

필자는 Firebase 데이터베이스의 "graylist"항목을 살펴보고 사용자 입력에 대해 확인하기 위해 정적 프로그램을 작성했습니다. 엔트리가 존재합니다. 필자는 항목을 잘 찾을 수 있지만, 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!"); 
} 

내가 최종 부울 배열이 얼마나 해키 실현을하지만, 심지어 나를 위해 작동하지 않습니다. 아이디어는 CountDownLatch를 사용하고 쓰기가 성공적 일 때만 카운트 다운합니다. graylist의 모든 항목을 읽고 CountDownLatch가 여전히 1이면 아무 것도 기록되지 않고 스레드를 종료하기 위해 카운트 다운해야하지만 부울은 작업이 성공했는지 여부를 결정합니다.

문제는 onComplete 메서드가 호출되기 전에 for 루프 이후에 if 블록에 도달하여 작업이 실패했다고 생각하고 (Firebase의 데이터베이스가 다르게 표시하더라도) 잘못된 경고가 출력되는 것 같습니다. .

사용자가 허용 목록에 추가되었거나 사용자를 찾을 수없는 경우 적절히 알릴 수 있도록 더 나은 방법을 생각해 볼 수 있습니까?

답변

0

Firebase 데이터베이스에서의 작업은 본질적으로 비동기이므로 어떤 방법 으로든 위의 코드가 작동하더라도 궁극적으로 코드의 많은 부분이 다음과 같은 기능을 처리하는 대신에 복잡한 작업을 수행하게됩니다. 너의 어플리케이션. 이로 인해 쉽게 유지할 수없는 코드가 생길 수 있습니다.

데이터베이스 요청을 처리하는 가장 간단하고 자연스러운 방법은 코드의 각 이벤트가 발생할 때마다 처리하는 것입니다.

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!"); 
       }); 
      } 
     } 
    }); 
} 
+0

onComplete가 별도의 스레드에 있고 JavaFX가 기본 스레드 외부에서 대화 메시지를 작성할 수 없기 때문에 불가능합니다. 다소 실망 스럽습니다. –

+0

이 게시물은 도움이 되나요? http://stackoverflow.com/questions/19755031/how-javafx-application-thread-works? AFAIK Firebase는 메인 스레드에서'onComplete' 콜백을 트리거하므로 JavaFX 스레드에서 UI를 호출해야합니다. – manouti

+0

BTW 'onComplete'가 별도의 스레드에서 호출되는지 확인 하시겠습니까? 안드로이드에서는 메인 스레드에서 호출되고 JVM에서는 동일합니다. 모든 경우에, 링크 된 포스트 ('Platform.runLater')에서 메커니즘을 시도 할 수 있습니다. – manouti

0

것은 내가 충분히하지 않아도이 모든 아이들의 실체가 확인되었고 일치가 발견 될 때 onComplete 메소드가 호출 될 때 성공적인 업데이트를 사용자에게 통보하고, 실패를 사용자에게 알리는 의미 평판 때문에 내 질문에 직접적으로 대답 할 수는 없습니다. 미안합니다.

실제로 Firebase에는 자체 스레드가 있습니다. grayRef.addListenerForSingleValueEvent를 호출하면 Firebase는 새 스레드를 열거 나 (이미 살아있는 독립 스레드 만 사용함) 원래 스레드는 작업이 완료된 것으로 간주하므로 즉시 if 블록으로 계속 진행합니다. 결과는 사용자가 보게됩니다.

따라서 Firebase가 작업을 완료하면 실제로는 기본 활동과 통신 할 수있는 청취자가 필요합니다. 안드로이드를 사용하지 않는다고 말했기 때문에 인터페이스와 리스너가 포함 된 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); 
      } 
     }); 
    } 
} 

사용자의 활동에 리스너를 연결하고 해당 메소드를 구현하기 만하면됩니다. 그래서 당신의 UI 스레드에서 ...

+0

원래 게시글에 명확하지 않은 경우 Android 애플리케이션이 아닙니다. 그것은 순수 자바입니다. –

+0

그러면 인터페이스와 수신기를 사용하는 두 번째 방법이 계속 적용됩니다. – tingyik90

관련 문제