4

Android に簡単な Facebook チャット アプリケーションを実装しようとしています。ユーザーがログインすると、アプリListActivityはユーザーのオンライン連絡先を列挙する新しいものを開き、項目をクリックするとActivity、会話が行われる別の項目が開きます。

ユーザーがログインする最初の画面は と呼ばれMainActivityます。これには 2 つEditTextの s が含まれています。1 つは FB ユーザー名用で、もう 1 つはパスワード用です。2 つのボタンもあります。s を空にする Clear ボタンEditTextと、クリックすると を介して次の AsyncTask を実行する OKボタンです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();
   }
}

私の問題は、2番目の画面が開かれるたびに、ListViewに何も表示されないことがよくありますが、時々表示されます。経由で連絡先を取得している部分にログメッセージを追加することにしconn.getRoster()ました。ほとんどの場合、への呼び出しconn.getRoster().getEntries.size()はゼロを返しますが、実際にブラウザ経由で Facebook にログインすると、ログインしていることがわかります。オンライン連絡先があります。しかし、私が理解していないのは、正しい数値が返されることがありますが、アプリケーションを実行するのはほぼ 10 億回に 1 回だけです。

誰か助けてください。このアプリは 4 時間後に期限が切れますが、コードに問題がないように見えるため、もう何をすべきかわかりません。

4

2 に答える 2

6

ここに投稿した翌日、この質問に対する答えを見つけました。どうやら、conn.login()が呼び出されると、ユーザーは認証され、Facebook サーバーは名簿アイテムの送信を開始します。ほとんどの場合、2 番目の画面に何も表示されない理由はstartActivity()、Facebook サーバーが名簿アイテムを含むパケットの送信を完了する前に、コードが EVEN への呼び出しに到達するためです。ただし、サーバーがパケットを送信するのに十分な速さであっても、startActivity()呼び出されて追加が中断され、オンライン連絡先がArrayList不完全になる場合があります。私が行った回避策は、サーバーがすべてのパケットを送信するのに十分な時間を確保できるように、afterListViewを呼び出して 5 ~ 10 秒の遅延を作成することでした。Thread.sleep()conn.login()

それはしばらくの間しか機能しませんでしたが、( を使用してVCard) 連絡先の写真を取得するという追加のタスクがある場合、30 秒の遅延でも十分ではありませんでした。次に、サーバーがパケットと VCard の送信をいつ完了したかを判断し、シグナルを受信した場合にのみ ArrayList への追加を続行する方法を見つける必要があります。

残念ながら、Smack のドキュメントを見ると、それを行う方法はないようです。しかし、それは私の目標が全体的に間違っていたからです。私がやろうとしていたのはこれです:

  1. フェイスブックにログインします。
  2. すべてのオンライン連絡先を取得します。
  3. それらを に入れますArrayList
  4. を開きますListActivity
  5. ArrayListの内容を表示しListActivityます。

これを行う必要がある場合:

  1. フェイスブックにログインします。
  2. を開きますListActivity
  3. すべての連絡先を取得します。
  4. ListView連絡先の存在に応じて動的に更新します (まだこの部分は行っていません)。

要するに、Smack API はリアルタイム イベントを処理するように設計されています。これはインスタント メッセージング ライブラリであるため、別の方法で設計する必要はなかったと思います。最初の例で私がやろうとしていたことは、どちらかというと静的なものでした。

于 2011-09-06T06:04:55.747 に答える
0

多分あなたも 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());
    }
}
于 2015-10-25T05:31:06.570 に答える