2017-02-01 2 views
1

Ich habe gelesen, dass Firebase seine Operationen auf Hintergrundthreads und seine Callbacks auf dem UI-Thread ausführt.Ausführen einer Blockierungsanforderung

Gibt es eine Möglichkeit, blockierende Firebase-Operationen auszuführen?

Zum Beispiel:

Ich weiß setValue() kein boolean zurückgibt, ich frage, ob es eine ähnliche API ist, die so etwas wie den Code unten tut

// we are in a background thread 

DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 

boolean success = ref.child("user").child("name").setValue("Arthur"); 

// code is blocked until operation completes 

Log.d("MY_TAG", "successfull operation:" + success); 

Antwort

1

Die FirebaseDatabase API tut keine Sperrform von setValue() enthalten. Sie können die zurück Task verwenden in Ihrem eigenen Code in einem Arbeiter (nicht-Main) Gewinde hinzufügen Blockieren:

boolean success = false; 
    DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 
    Task task = ref.child("user").child("name").setValue("Arthur"); 

    try { 
     Tasks.await(task); 
     success = task.isSuccessful(); 
    } catch (ExecutionException e) { 
     e.printStackTrace(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    Log.d("MY_TAG", "successfull operation:" + success); 

A Semaphore lesen kann für eine Blockierung verwendet werden. Da die Listener-Callbacks im Hauptthread ausgeführt werden, kann dieser Code nur in einem anderen Thread ausgeführt werden. Wenn es im Hauptthread ausgeführt wird, wird es blockiert.

final Semaphore sem = new Semaphore(0); 

    DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 

    ref.child("user").child("name").addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      String name = dataSnapshot.getValue(String.class); 
      Log.i("MY_TAG", "Name=" + name); 
      sem.release(); 
     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 
      Log.e("MY_TAG", "onCancelled: " + databaseError.getMessage()); 
      sem.release(); 
     } 
    }); 

    try { 
     sem.acquire(); 
    } catch (InterruptedException e) { 
     Log.w("MY_TAG", "Interrupted"); 
    } 

Sie können auch eine Task für eine Blockierung lesen verwenden (aus dem Hauptthread):

final TaskCompletionSource<DataSnapshot> taskSource = new TaskCompletionSource<>(); 
    final Task<DataSnapshot> task = taskSource.getTask(); 

    DatabaseReference ref = FirebaseDatabase.getInstance().getReference(); 

    ref.child("user").child("name").addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      taskSource.setResult(dataSnapshot); 
     } 

     @Override 
     public void onCancelled(DatabaseError databaseError) { 
      taskSource.setException(databaseError.toException()); 
     } 
    }); 

    try { 
     Tasks.await(task); 

     String name = task.getResult().getValue(String.class); 
     Log.i("MY_TAG", "Name=" + name); 
    } catch (ExecutionException e) { 
     Log.e("MY_TAG", "Read failed: " + task.getException().getMessage()); 
    } catch (InterruptedException e) { 
     Log.w("MY_TAG", "Read interrupted"); 
    } 
+0

Dank Qbix! Dies scheint den Trick für setValue() zu tun. Gibt es eine Möglichkeit, das gleiche mit "Lese" -Operationen zu tun? (d. h. Ersetzen von DatabaseReference addListenerForSingleValueEvent() durch einen Task, auf den ich warten kann? – dors

+1

@dors: Ich habe meine Antwort aktualisiert. –

Verwandte Themen