Проблема со Smack в приложении чата Facebook для Android: Connection.getRoster (). GetEntries () всегда пуст - PullRequest
3 голосов
/ 24 августа 2011

Я пытаюсь реализовать простое приложение чата Facebook на Android.Он позволяет пользователю войти в систему, после чего приложение открывает новый ListActivity, перечисляющий онлайн-контакты пользователя, и после нажатия на элемент открывается еще один Activity, где происходит их разговор.

Первый экрангде пользователь входит в систему, называется MainActivity.Он содержит два EditText s: один для имени пользователя FB, а другой для пароля.Есть также две кнопки: Очистить, которая очищает EditText s, и OK, которая при нажатии выполняет следующую AsyncTask через 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();
   }
}

Моя проблема в том, что всякий раз, когда второй экранпри открытии ListView часто ничего не показывает, НО ЭТО ИНОГДА ДЕЛАЕТ .Я решил добавить сообщения журнала в ту часть, где я получаю контакты с помощью conn.getRoster(), и обнаружил, что в большинстве случаев звонок на conn.getRoster().getEntries.size() возвращает ноль, но когда я действительно захожу в Facebook через браузер,Я вижу, что у меня есть онлайн-контакты.Однако я не понимаю, почему он иногда возвращает правильное число, но только один раз почти каждый миллиард раз я запускаю приложение.

Кто-нибудь поможет, пожалуйста?Это приложение выйдет через четыре часа, и я больше не знаю, что делать, так как в моем коде нет ничего плохого.

Ответы [ 2 ]

6 голосов
/ 06 сентября 2011

Я нашел ответ на этот вопрос на следующий день после того, как разместил его здесь.По-видимому, когда вызывается conn.login(), пользователь проходит проверку подлинности, и сервер Facebook начинает отправлять элементы списка.Причина, по которой в большинстве случаев на втором экране ничего не появляется, заключается в том, что код достигает вызова startActivity() ДАЖЕ, пока сервер Facebook не завершил отправку пакетов, содержащих элементы списка.Однако иногда сервер достаточно быстр для отправки пакетов, но вызывается startActivity(), и добавление к ArrayList прерывается, что приводит к неполному ListView ваших онлайн-контактов.Обходной путь, который я сделал, это вызвать Thread.sleep() после conn.login() и создать задержку в 5–10 секунд, чтобы у сервера было достаточно времени для отправки всех пакетов.

Это работало только некоторое времяно когда у меня появилась дополнительная задача получения даже фотографий моих контактов (используя VCard), даже 30-секундной задержки было недостаточно.Затем вы должны найти способ определить, когда сервер завершил отправку пакетов и VCards, и приступить к добавлению в ArrayList только при получении сигнала.

К сожалению, при просмотре документации по Smackкажется, способ сделать это.Но это потому, что моя цель была в целом неправильной.Я пытался сделать следующее:

  1. Войти в Facebook.
  2. Получить все онлайн-контакты.
  3. Поместить их в ArrayList.
  4. Открыть ListActivity.
  5. Показать содержимое ArrayList в ListActivity.

Когда это должно быть сделано:

  1. Войдите в Facebook.
  2. Откройте ListActivity.
  3. Получить ВСЕ ваши контакты.
  4. Динамически обновляйте ListView в зависимости от присутствия ваших контактов (до сих пор не выполнил эту часть).

Короче говоря, API Smack был разработан для обработки событий в реальном времени, и, поскольку это библиотека мгновенных сообщений, я не думаю, что она должна иметьбыл разработан иначе.То, что я пытался сделать в первом примере, было довольно статичным.

0 голосов
/ 25 октября 2015

Может быть, вы также 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());
    }
}
...