2017-04-23 60 views
1

我試圖從我的firebase數據庫中獲取項目列表......但是我有一個獲取它們的問題。 我的代碼看起來或多或少是這樣的:查詢來自Firebase的數據

List<Items> itemsList; 

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_work_items_report); 

    itemsList = GetItems(); 
} 

而且應該返回我的項目的方法是這樣的:

private ArrayList<Items> GetItems(){ 
    DatabaseReference database = FirebaseDatabase.getInstance().getReference(); 
    DatabaseReference ref = database.child("items"); 
    final ArrayList<Items> itemsRez = new ArrayList<Items>(); 
    Query itemsQuery = ref.orderByChild("type"); 

    itemsQuery.addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      if (dataSnapshot.exists()) { 
       for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) { 
        Items item = singleSnapshot.getValue(Items.class); 
        itemsRez.add(item); 
       } 
      } 
     } 
     @Override 
     public void onCancelled(DatabaseError databaseError) { 

     } 
    }); 
    return itemsRez; 
} 

的GetItems()總是返回我一個空列表,這還挺有道理,因爲沒有什麼可以在我返回這個列表之前觸發onDataChange事件,所以我的問題是......我怎樣才能讓這個方法返回數據庫中的項目列表?

+0

什麼是錯的利用內幕onDataChange數據?阻塞UI線程是一個壞主意。 – Selvin

+0

你說得對,我認爲最好在onDataChange中做。但是,即使這不是我所做的最好的想法,我該怎麼做呢? –

+0

移動onDataChange中使用itemsList的代碼 – Selvin

回答

3

當您致電addListenerForSingleValueEvent()時,Firebase客戶端開始從服務器加載數據,這可能需要一些時間。爲了防止阻止你的應用程序(這將導致一個應用程序不響應對話框),它將數據加載到一個單獨的線程中。因此,當數據加載時,主線程繼續並返回當前狀態itemsRez,這是一個空列表。

這是最簡單的,看看這個,如果你添加一些日誌語句代碼:

private ArrayList<Items> GetItems(){ 
    DatabaseReference database = FirebaseDatabase.getInstance().getReference(); 
    DatabaseReference ref = database.child("items"); 
    final ArrayList<Items> itemsRez = new ArrayList<Items>(); 
    Query itemsQuery = ref.orderByChild("type"); 

    System.out.println("Attaching listener"); 
    itemsQuery.addListenerForSingleValueEvent(new ValueEventListener() { 
     @Override 
     public void onDataChange(DataSnapshot dataSnapshot) { 
      if (dataSnapshot.exists()) { 
       for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()) { 
        Items item = singleSnapshot.getValue(Items.class); 
        itemsRez.add(item); 
       } 
      } 
      System.out.println("Received "+itemsRez.size()+" items"); 
     } 
     @Override 
     public void onCancelled(DatabaseError databaseError) { 

     } 
    }); 
    System.out.println("Returning "+itemsRez.size()+" items"); 
    return itemsRez; 
} 

相反,你可能會想到,這將打印日誌順序如下:

附加聽衆

返回0項

收到的項目

您的問題的一個常見解決方案是重新構建您的代碼目標。不要寫「先拿到物品,然後再用它們」,把代碼寫成「開始獲取物品,然後當它們進入時,對它們進行abc處理」。在代碼中,這意味着您需要將需要itemsRec的代碼移動到onDataChange方法中,該方法將在正確的時刻調用它:項目已加載。

另見: