2014-11-21 89 views
2

我想從單個事件調用的偵聽器獲取的方法中返回數據。但是,它看起來像我返回的對象正在實際返回語句後填充。我明白,獲取數據快照的調用是異步的,這就是發生這種情況的原因。我怎樣才能避免這種情況?我試過信號量和原子布爾值,但它似乎鎖定了我的應用程序。這是有問題的代碼。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; 
} 

注:我試過原子布爾設置爲false,則設置爲true,偵聽器內,然後有一段時間(布爾==假)我回來之前,但這會導致我的應用程序的鎖定。

+0

你不能避免這一點。異步性是現代網絡中給出的,你必須接受它。 – 2014-11-21 12:40:47

+0

可能重複[將父範圍中的變量傳遞給回調函數](http://stackoverflow.com/questions/26297654/passing-variable-in-parent-scope-to-callback-function) – 2014-11-21 12:42:17

回答

4

您試圖做的是讓Firebase同步。

這可能是可能的,但這是一個非常糟糕的主意。它會冒險在主線程上進行網絡操作。使Android非常暴躁的模式。請參閱有關doing network stuff on a separate thread的一般指導。

因此,確定在不同的線程上執行網絡操作是件好事,我對你有好消息。 Firebase已自動執行此操作!指定回叫,就像在AsyncTask中那樣。

更改您的getter以接受回調作爲參數。

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

對不起,這是一個超級老問題,但非常有用。你將如何定義Callback類'AwesomeCallback'? – beckah 2017-01-18 16:26:36

+0

我通常定義一個內部類,但它是一個任意的選擇。你只需要一個類來定義你從另一個方法調用的函數。 – mimming 2017-01-25 21:57:22