Android的Facebook聊天应用程序中的Smack问题:Connection.getRoster()。getEntries()始终为空

时间:2011-08-24 03:40:06

标签: android smack facebook-chat

我正在尝试在Android上实现一个简单的Facebook聊天应用程序。它允许用户登录,之后应用程序会打开一个新的ListActivity枚举用户的在线联系人,点击某个项目后,另一个Activity会打开他们进行对话的位置。

用户登录的第一个屏幕称为MainActivity。它包含两个EditText s:一个用于FB用户名,另一个用于密码。还有两个按钮:清除,清空EditText,然后单击确定,通过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通过浏览器,我可以看到我确实有在线联系人。但是,我不明白为什么它有时会返回正确的数字,但是在我运行应用程序的时候几乎每十亿次才会返回一次。

有人帮忙吗?这个应用程序将在四个小时后到期,我不知道该怎么做,因为我的代码似乎没有任何问题。

2 个答案:

答案 0 :(得分:6)

我在这里发布这个问题的第二天就找到了这个问题的答案。显然,当调用conn.login()时,用户将被认证,Facebook服务器开始发送名册项目。大多数时候第二个屏幕中没有任何内容出现的原因是代码到达startActivity()的呼叫,甚至在Facebook服务器完成发送包含名册项目的数据包之前。但有时,服务器的速度足以发送数据包,但调用了startActivity(),并且ArrayList的添加中断,导致您的在线联系人ListView不完整。我做的一个解决方法是在Thread.sleep()之后调用conn.login()并创建一个5到10秒的延迟,以便服务器有足够的时间发送所有数据包。

仅仅工作了一段时间但是当我有额外的任务来检索我的联系人的照片(使用VCard)时,即使是30秒的延迟也是不够的。您应该找到一种方法来确定服务器何时完成发送数据包和VCard,并在获得信号时继续添加到ArrayList。

不幸的是,看看Smack文档,似乎没有办法做到这一点。但那是因为我的目标总的来说是错误的。我试图做的是:

  1. 登录Facebook。
  2. 获取所有在线联系人。
  3. 将它们放入ArrayList
  4. 打开ListActivity
  5. ArrayList
  6. 中显示ListActivity内容

    应该这样做:

    1. 登录Facebook。
    2. 打开ListActivity
    3. 获取所有联系人。
    4. 根据您的联系人的存在动态更新ListView(尚未完成此部分)。
    5. 简而言之,Smack API设计用于处理实时事件,因为它是一个即时消息库,我认为不应该设计它。我在第一个例子中试图做的是相当静态的。

答案 1 :(得分: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());
    }
}