2011-08-24 58 views
3

我試圖在Android上實現一個簡單的Facebook聊天應用程序。它允許用戶登錄,之後應用程序將打開一個新的ListActivity枚舉用戶的在線聯繫人,並且一旦點擊一個項目,另一個Activity將打開他們的對話發生的地方。Android的Facebook聊天應用程序中的Smack問題:Connection.getRoster()。getEntries()始終爲空

用戶登錄的第一個屏幕稱爲MainActivity。它包含兩個EditText s:一個用於FB用戶名,另一個用於密碼。還有兩個按鈕:清除,其清空EditText秒,OK,這在點擊,通過new LoginTask().execute()執行以下的AsyncTask:

class LoginTask extends AsyncTask<Void, Void, Void> { 
    private ProgressDialog loading; 

    @Override 
    protected void onPreExecute() { 
     loading = ProgressDialog.show(MainActivity.this, "", "Loading..."); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     // setup XMPP connection 
     ConnectionConfiguration config = new ConnectionConfiguration(
      "chat.facebook.com", 5222, "chat.facebook.com"); 
     config.setDebuggerEnabled(true); 
     config.setSASLAuthenticationEnabled(true); // TRUE for fb 
     conn = new XMPPConnection(config); 

     try { 
     // attempt login 
     conn.connect(); 
     SASLAuthentication.supportSASLMechanism("PLAIN", 0); 
     conn.login(login_field.getText().toString(), 
       pwd_field.getText().toString(), ""); 

     Log.d("TRACE", "isAuthenticated? " + conn.isAuthenticated()); 

     // list online contacts 
     Roster roster = conn.getRoster(); 
     Collection<RosterEntry> entries = roster.getEntries(); 
     Log.d("TRACE", "entries.size()=" + entries.size()); 
     for (RosterEntry e : entries) { 
      Log.d("PRESENCE", e.getUser() + "=" + roster.getPresence(e.getUser()).isAvailable()); 
      if (roster.getPresence(e.getUser()).isAvailable()) { 
       HashMap<String, String> contact = new HashMap<String, String>(); 
       contact.put(NAME_KEY, e.getName()); 
       contact.put(USERJID_KEY, e.getUser()); 
       Log.d("ADD", "NAME_KEY=" + e.getName() + " USERJID_KEY=" + e.getUser()); 
       contacts.add(contact); 
      } 
     } 
     Collections.sort(contacts, new ContactComparator()); // sort alphabetically 
     Log.d("TRACE", "MainActivity.contacts.size(): " + contacts.size()); 

     Intent in = new Intent(MainActivity.this, ContactList.class); 
     startActivity(in); 
     } catch (Exception e) { 
     Log.d("EXCEPTION", e.toString()); 
     } 

     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     loading.dismiss(); 
    } 
} 

我的問題是,每當第二屏幕打開,ListView中往往沒有按不會顯示任何內容,但是它有時會出現。我決定將日誌消息添加到我通過conn.getRoster()檢索聯繫人的部分,並且我發現大多數情況下,致電conn.getRoster().getEntries.size()的電話會返回零,但當我通過瀏覽器實際登錄到Facebook時,我可以看到我確實有在線聯繫人。然而,我不明白爲什麼它有時會返回正確的數字,但在我運行該應用程序的幾乎每十億次中只有一次。

有人幫忙嗎?這個應用程序在四個小時內到期,我不知道該怎麼辦了,因爲我的代碼似乎沒有問題。

回答

6

我在這裏發佈後發現了這個問題的答案。很顯然,當conn.login()被調用時,用戶將被認證並且Facebook服務器開始發送名單項目。在大多數情況下,第二個屏幕上什麼也沒有顯示,原因是代碼在012服務器完成發送包含名單項目的數據包之前,已經調用了startActivity()。但有時候,服務器發送數據包的速度很快,但調用了startActivity(),並且添加到ArrayList會中斷,導致您的在線聯繫人不完整ListView。我所做的解決方法是在conn.login()之後調用Thread.sleep(),並創建5到10秒的延遲,以便服務器有足夠的時間發送所有數據包。

這只是一段時間的工作,但是當我有添加任務甚至檢索我的聯繫人的照片(使用VCard),甚至30秒的延遲是不夠的。然後,您應該找到一種方法來確定服務器何時完成發送數據包和VCards,並只在獲取信號時才繼續添加到ArrayList。

不幸的是,看着Smack文檔,似乎沒有辦法做到這一點。但那是因爲我的目標總體上是錯誤的。我試圖做的是這樣的:

  1. 登錄Facebook。
  2. 獲取所有在線聯繫人。
  3. 把它們放在ArrayList
  4. 打開ListActivity
  5. 顯示ListActivity中的ArrayList內容。

當它應該是這樣:在Facebook的

  1. 日誌。
  2. 打開ListActivity
  3. 獲取所有聯繫人。
  4. 根據您的聯繫人的存在動態更新ListView(仍未完成此部分)。

簡而言之,Smack API被設計爲處理實時事件,因爲它是一個即時消息庫,所以我認爲它不應該被設計成其他方式。我在第一個例子中試圖做的是相當靜態的。

+1

對不起,我想我是新來的Android,當我寫這個答案。很確定你可以通過'AsyncTask'做延遲加載。 –

0

也許你還consifer roster.reloadAndAwait()

public void getRoaster(final Callback<Collection<RosterEntry>> callback) { 
    final Roster roster = Roster.getInstanceFor(connection); 
    if (!roster.isLoaded()) 
    try { 
     roster.reloadAndWait(); 
    } catch (SmackException.NotLoggedInException | SmackException.NotConnectedException | InterruptedException e) { 
     e.printStackTrace(); 
    } 

    Collection<RosterEntry> entries = roster.getEntries(); 
    for (RosterEntry entry : entries) { 
     android.util.Log.d(AppConstant.PUBLIC_TAG, entry.getName()); 
    } 
}