1

Я пытаюсь использовать Семафор, чтобы дождаться моего значения firebaseEventListener. У меня есть информация о пользователе с 6 различными полями, которые пользователь должен заполнить. Когда пользователь сохраняет свою информацию, я хочу сделать «все или ничего». Некоторая информация пользователя не может быть дублирована ... например, имя пользователя, адрес электронной почты и номер телефона. Я использую firebase и в настоящее время общая идея имеет формат:Android: wait forbainbase 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; 
    } 

} 

Сейчас семафор не отпуская ... Было интересно, если кто-нибудь может помочь мне здесь. Без семафора оператор возврата будет срабатывать до того, как запрос firebase может завершиться ...

+0

См http://stackoverflow.com/questions/33203379/setting-singleton-property-value-in-firebase-listener –

ответ

5

Методы обратного вызова слушателя работают по основному потоку. Если вы вызываете alreadyInUse() в основном потоке, он блокирует поток на semaphore.acquire(), предотвращая запуск обратных вызовов и освобождение семафора.

Возможно, вы найдете this answer.

6

Как уже упоминалось, вы можете использовать Firebase Task API, представленный на Google 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(); 
} 

Если какой-либо из них не вы необходимо отменить операции. Так как это может быть threated от одной задачи, вы можете создать Continuation задачу:

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(); 
    } 
} 
Смежные вопросы