Android 版 Facebook 聊天应用程序中的 Smack 问题:Connection.getRoster().getEntries() 始终为空
我正在尝试在 Android 上实现一个简单的 Facebook 聊天应用程序。它允许用户登录,然后应用程序打开一个新的 ListActivity
枚举用户的在线联系人,单击某个项目后,将打开另一个 Activity
进行对话。
用户登录的第一个屏幕称为 MainActivity
。它包含两个 EditText
:一个用于 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 时,我可以看到我确实有在线联系人。但我不明白的是,为什么它有时会返回正确的数字,但在我运行该应用程序的几乎每十亿次中只返回一次。
有人帮忙吗?这个应用程序将在四个小时内到期,但我不知道该怎么办了,因为我的代码似乎没有任何问题。
I'm trying to implement a simple Facebook chat application on Android. It lets the user login, after which the app opens a new ListActivity
enumerating the user's online contacts, and upon clicking on an item, another Activity
opens where their conversation will take place.
The first screen where the user logs in is called MainActivity
. It contains two EditText
s: one for the FB username, and the other for password. There are also two buttons: Clear, which empties the EditText
s, and OK, which upon click, executes the following AsyncTask via new LoginTask().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();
}
}
My problem is that whenever the second screen is opened, the ListView often doesn't show anythying, BUT IT SOMETIMES DOES. I decided to add log messages to the part where I'm retrieving the contacts via conn.getRoster()
and I found out that most of the time, a call to conn.getRoster().getEntries.size()
returns a zero, but when I actually login to Facebook via browser, I can see that I do have online contacts. What I don't understand, though, is why it sometimes returns the correct number, but only once in almost every billion times I run the application.
Somebody help, please? This app's due in four hours and I don't know what to do anymore since there seems to be nothing wrong with my code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在这里发布这个问题的第二天就找到了答案。显然,当调用
conn.login()
时,用户将通过身份验证,Facebook 服务器开始发送名册项目。大多数时候第二个屏幕上什么也没有出现的原因是,即使在 Facebook 服务器发送包含名册项目的数据包之前,代码就到达了对startActivity()
的调用。但有时,服务器的速度足以发送数据包,但startActivity()
被调用,并且添加到ArrayList
会被中断,从而导致不完整的ListView< /code> 您的在线联系人。我采取的解决方法是在
conn.login()
之后调用Thread.sleep()
并创建 5 到 10 秒的延迟,以便服务器有足够的时间发送所有数据包。这种方法只工作了一段时间,但当我还需要检索联系人的照片(使用
VCard
)时,即使 30 秒的延迟也不够。您应该找到一种方法来确定服务器何时完成发送数据包和 VCard,并仅在收到信号时才继续添加到 ArrayList。不幸的是,查看 Smack 文档,似乎没有办法做到这一点。但那是因为我的目标总体来说是错误的。我想做的是:
ListActivity
。ListActivity
中显示ArrayList
内容。何时应该这样做:
ListActivity
。ListView
(尚未完成这部分)。简而言之,Smack API 被设计为处理实时事件,并且因为它是一个即时消息传递库,所以我认为它不应该被设计成其他方式。我在第一个示例中尝试做的事情是相当静态的。
I found the answer to this question the day after I posted it here. Apparently, when
conn.login()
is called, the user becomes authenticated and the Facebook server starts sending the roster items. The reason why nothing appears in the second screen most of the time is that the code reaches the call tostartActivity()
EVEN BEFORE the Facebook server is done sending the packets containing the roster items. Sometimes, though, the server is fast enough to send the packets butstartActivity()
is called and adding to theArrayList
becomes interrupted, resulting to an incompleteListView
of your online contacts. A workaround I did was to callThread.sleep()
afterconn.login()
and create a 5- to 10-second delay so that the server would have enough time to send all the packets.That worked only for a while but when I has the added task of retrieving even the photos of my contacts (using
VCard
), even a 30-second delay wasn't enough. You should find a way then to determine when the server is done sending packets and the VCards and proceed with adding to the ArrayList only when you get the signal.Unfortunately, looking at the Smack documentation, there doesn't seem to be a way to do that. But that's because my goal was, overall, wrong. What I was trying to do is this:
ArrayList
.ListActivity
.ArrayList
contents in theListActivity
.When it should be doing this:
ListActivity
.ListView
depending on your contacts' presence (still haven't done this part).In short, the Smack API has been designed to handle real-time events, and because it's an instant messaging library, I don't think it should have been designed otherwise. What I was trying to do in the first example was rather static.
也许您还考虑 roster.reloadAndAwait()
Maybe you also consifer roster.reloadAndAwait()