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

我正试图在Android上实现一个简单的Facebook聊天应用程序.它允许用户登录,之后应用程序打开一个新的ListActivity,枚举用户的在线联系人,点击一个项目后,另一个活动将打开他们的对话将发生的地方.

用户登录的第一个屏幕称为MainActivity.它包含两个EditTexts:一个用于FB用户名,另一个用于密码.还有两个按钮:Clear,清空EditTexts,OK,点击后,通过新的LoginTask()执行以下AsyncTask.execute():

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时,我可以看到我确实有在线联系人.但是,我不明白为什么它有时会返回正确的数字,但是在我运行应用程序的时候几乎每十亿次只返回一次.

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

解决方法:

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

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

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

>登录Facebook.
>获取所有在线联系人.
>将它们放在ArrayList中.
>打开ListActivity.
>在ListActivity中显示ArrayList内容.

什么时候应该这样做:

>登录Facebook.
>打开ListActivity.
>获取所有联系人.
>根据您的联系人的存在动态更新ListView(仍然没有完成此部分).

简而言之,Smack API设计用于处理实时事件,因为它是一个即时消息库,我认为不应该设计它.我在第一个例子中试图做的是相当静态的.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...