2014-11-21 4 views
2

Я пытаюсь вернуть данные в методе, который я получаю от слушателя для вызова одного события. Однако, похоже, что объект, который я возвращаю, заполняется после фактического оператора return. Я понимаю, что вызов для получения моментального снимка данных является асинхронным, и именно поэтому это происходит. Как я могу избежать этого? Я пробовал Семафоры и Atomic Booleans, но, похоже, я заблокировал свое приложение. Вот этот код.Firebase: Как захватить данные в реальном времени

static User getUser(String uid){ 
    /**** created final object here for returning ****/ 
    final User returnUser = new User(); 

    Firebase userRef = new Firebase("<firebase-url>/users/"+uid+"/"); 

    userRef.addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      Log.d("MT", "attempting to instantiate user"); 
      User tempUser = dataSnapshot.getValue(User.class); 

      /**** preparing object for return ****/ 
      returnUser.setNickname(tempUser.getNickname()); 
      returnUser.setAge(tempUser.getAge()); 
      returnUser.setEmail(tempUser.getEmail()); 
      returnUser.setHeight(tempUser.getHeight()); 
      returnUser.setSex(tempUser.getSex()); 
      returnUser.setWeight(tempUser.getWeight()); 

      //This logs actual information 
      Log.d("MT", returnUser.getNickname() + " =======INSTANTIATED=======."); 
      Log.d("MT", returnUser.getEmail()); 
      Log.d("MT", new Double(returnUser.getAge()).toString()); 
      Log.d("MT", new Double(returnUser.getHeight()).toString()); 
      Log.d("MT", returnUser.getSex()); 
      Log.d("MT", new Double(returnUser.getWeight()).toString()); 
     } 

     @Override 
     public void onCancelled(FirebaseError firebaseError) { 
      Log.d("MT", "Something went wrong."); 
     } 
    }); 
    Log.d("MT", returnUser.getNickname()); //This logs an empty string. 
    return returnUser; 
} 

Примечание: Я пытался Atomic логическое значение ЛОЖЬ, то значение ИСТИНА в слушателя, а затем иметь какое-то время (булево == ложь), прежде чем я вернусь, но это приводит к блокировки моего приложения.

+0

Вы не можете избежать этого. Асинхронность - это данность в современной сети, и вы должны ее принять. –

+0

Возможный дубликат [Передача переменной в родительской области для функции обратного вызова] (http://stackoverflow.com/questions/26297654/passing-variable-in-parent-scope-to-callback-function) –

ответ

4

Что вы пытаетесь сделать, так это сделать синхронную Firebase.

Это может быть возможно, но это очень плохая идея. Это может привести к сетевым операциям в основном потоке. Модель, которая делает Android очень сварливым. См. Их общее руководство по doing network stuff on a separate thread.

Итак, установив, что полезно делать сетевые материалы в другом потоке, у меня есть хорошие новости для вас. Firebase уже делает это автоматически! Укажите обратный вызов, как и в AsyncTask.

Измените свой приемник, чтобы принять обратный вызов в качестве параметра.

public void getUser(String uid, AwesomeCallback callback){ 

    Firebase userRef = new Firebase("<firebase-url>/users/"+uid+"/"); 

    userRef.addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      Log.d("MT", "attempting to instantiate user"); 
      User returnUser = new User(); 
      User tempUser = dataSnapshot.getValue(User.class); 

      /**** preparing object for return ****/ 
      returnUser.setNickname(tempUser.getNickname()); 
      returnUser.setAge(tempUser.getAge()); 
      returnUser.setEmail(tempUser.getEmail()); 
      returnUser.setHeight(tempUser.getHeight()); 
      returnUser.setSex(tempUser.getSex()); 
      returnUser.setWeight(tempUser.getWeight()); 

      //This logs actual information 
      Log.d("MT", returnUser.getNickname() + " =======INSTANTIATED=======."); 
      Log.d("MT", returnUser.getEmail()); 
      Log.d("MT", new Double(returnUser.getAge()).toString()); 
      Log.d("MT", new Double(returnUser.getHeight()).toString()); 
      Log.d("MT", returnUser.getSex()); 
      Log.d("MT", new Double(returnUser.getWeight()).toString()); 

      callback.doCallback(returnUser); 
     } 

     @Override 
     public void onCancelled(FirebaseError firebaseError) { 
      Log.d("MT", "Something went wrong."); 
     } 
    }); 
} 

А потом, делать свою работу с помощью функции обратного вызова

public class SomeAwesomeActivity extends Activity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     someObject.getUser("uid123", new AwesomeCallback() { 
      @Override 
      public void doCallback(User user) { 
       // Do cool stuff with that user object here 
      } 
     }); 
    } 
} 

Если вы еще не сделали много программирования обратного вызова в прошлом, это немного странно, и это займет некоторое время привыкнуть к нему. Однако, как только вы освоите его, разработка Android идет гораздо плавнее. От этого шаблона зависит множество конструкций, встроенных в Android SDK.

+0

жаль, что это супер старый вопрос, но очень полезный. Как бы вы определили класс обратного вызова 'AwesomeCallback'? – beckah

+0

Обычно я определяю внутренний класс, но это был произвольный выбор. Вам просто нужен класс, который определяет функцию, которую вы вызываете из другого метода. – mimming