【问题标题】:Problem with Smack in Facebook chat app for Android: Connection.getRoster().getEntries() is always emptyAndroid 版 Facebook 聊天应用程序中的 Smack 问题:Connection.getRoster().getEntries() 始终为空
【发布时间】:2011-11-02 11:10:29
【问题描述】:

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

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

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

【问题讨论】:

    标签: android smack facebook-chat


    【解决方案1】:

    我在此处发布此问题后的第二天就找到了答案。显然,当conn.login() 被调用时,用户通过了身份验证,Facebook 服务器开始发送花名册项目。大多数时候第二个屏幕上什么都没有出现的原因是代码到达了对startActivity()的调用,即使在Facebook服务器完成发送包含名册项目的数据包之前。但是,有时,服务器速度足以发送数据包,但调用 startActivity() 并添加到 ArrayList 会被中断,从而导致您的在线联系人的 ListView 不完整。我的解决方法是在conn.login() 之后调用Thread.sleep() 并创建5 到10 秒的延迟,以便服务器有足够的时间发送所有数据包。

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

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

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

    什么时候应该这样做:

    1. 登录 Facebook。
    2. 打开ListActivity
    3. 获取所有联系人。
    4. 根据您的联系人的存在动态更新ListView(这部分还没有完成)。

    简而言之,Smack API 旨在处理实时事件,并且因为它是一个即时消息库,所以我认为它不应该被设计为其他方式。我在第一个示例中尝试做的是相当静态的。

    【讨论】:

    • 对不起,当我写这个答案时,我想我是 Android 新手。很确定您可以通过AsyncTask 进行延迟加载。
    【解决方案2】:

    也许你也同意 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());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-19
      • 2015-10-04
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多