1

내 firebase valueEventListener를 기다리는 데 세마포어를 사용하려고합니다. 사용자가 작성해야하는 6 가지 필드가있는 사용자 정보 활동이 있습니다. 사용자가 정보를 저장하면 "모두 또는 아무것도 없음"유형의 검사를 수행하려고합니다. 특정 사용자 정보 (예 : 사용자 이름, 전자 메일 및 전화 번호)는 복제 할 수 없습니다. 나는 중포 기지를 사용하고 현재 일반 아이디어는 형식이다 :Android : firebase valueEventListener 대기

void saveUserInfo(){ 
    if(field1 exist in database){ 
     return; 
    } 
    . 
    . 
    . 
    if(field6 exist in database){ 
     return; 
    } 

    savefield1(); 
    . 
    . 
    . 
    savefield6(); 
} 

오전 데 문제는 값이 이미 데이터베이스에 존재하는지 여부를 확인하는 방법입니다. 아무도 여기에 나를 도울 수 있다면

public boolean alreadyInUse(String key, String value) throws InterruptedException { 

    final StringBuilder done = new StringBuilder(""); 
    final Semaphore semaphore = new Semaphore(0); 

    mDatabase.child(key).child(value).addListenerForSingleValueEvent(new ValueEventListener() { 

     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      String result = dataSnapshot.getValue(String.class); 
      if(result == null){ 
       Log.d("WorkoutLog", "result: null"); 
       done.append("false"); 
       semaphore.release(); 
       return; 
      } 
      else if(result.equals(uID)){ 
       Log.d("WorkoutLog", "result: " + result.toString()); 
       done.append("false"); 
       semaphore.release(); 
       return; 
      } 
      else{ 
       Log.d("WorkoutLog", "result: " + result.toString()); 
       done.append("true"); 
       semaphore.release(); 
       return; 
      } 

     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 

     } 
    }); 


    semaphore.acquire(); 
    if(done.equals("true")){ 
     return true; 
    } 
    else if(done.equals("false")){ 
     return false; 
    } 
    else{ 
     Log.d("WorkoutLog", "Shouldn't be here"); 
     return true; 
    } 

} 

는 지금 세마포어가 해제되지 ... 궁금 : 여기에 내 현재의 방법이다. semaphore가 없으면 firebase 쿼리가 완료되기 전에 return 문이 실행됩니다.

+0

참조 http://stackoverflow.com/questions/33203379/setting-singleton-property-value-in-firebase-listener : 이것은 하나의 작업에서 threated 할 수 있기 때문에, 당신은 Continuation 작업을 만들 수 있습니다 –

답변

5

리스너 콜백 메소드는 메인 스레드에서 실행됩니다. 주 스레드에서 alreadyInUse()을 호출하면 스레드가 semaphore.acquire()으로 차단되어 콜백이 실행되지 않고 세마포어가 해제되지 않습니다.

관련 질문에 도움이되는 this answer이 있습니다.

6

Firebase Task APIGoogle I/O 2016에 표시 할 수 있습니다.

Task<?>[] tasks = new Task[] { 
    saveUserName(username), 
    saveFriends(friends), 
    saveOtherStuff(stuff) 
}; 

Tasks.whenAll(tasks) 
    .continueWithTask(new RollbackIfFailure()) 
    .addOnCompleteListener(this) 
    .addOnFailureListener(this); 

수정이 병렬로 실행하는 각 단계는 다음과 같이 그들의 각 하나에 대한 Task를 반환하는 방법을 만들 수 있습니다 경우

public Task<String> saveUserName(final String username) { 
    final TaskCompletionSource<String> tcs = new TaskCompletionSource<>(); 

    mDatabase.child("users") 
     .child(username) 
     .addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      String username = dataSnapshot.getValue(String.class); 
      if (null == username) { 
       tcs.setResult(null); 
      } else { 
       tcs.setException(new IllegalStateException(username)); 
      } 
     } 

     @Override 
     public void onCancelled(FirebaseError firebaseError) { 
      tcs.setException(new IOException(TAG, firebaseError.toException())); 
     } 
    }); 

    return tcs.getTask(); 
} 

그 중 하나가 실패하면을, 당신 작업을 롤백해야합니다.

class RollbackIfFailure implements Continuation<Void, Task<Void>> { 
    @Override 
    public Task<Void> then(@NonNull Task<Void> task) throws Exception { 

     final TaskCompletionSource<Void> tcs = new TaskCompletionSource<>(); 

     if (task.isSuccessful()) { 
      tcs.setResult(null); 
     } else { 
      // Rollback everything 
     } 

     return tcs.getTask(); 
    } 
}