A Day In The Life

とあるプログラマの備忘録

GTalk系イベントリスナーの使い方

com.google.android.gtalkserviceパッケージには以下のようなイベントリスナーがあります。

  • IChatListener
  • IGroupChatInvitationListener
  • IRosterListener
これらのイベントリスナーは普通のイベントリスナー(たとえばView.OnClickListener)のようにActivityで使えません。

なぜかというとGTalkサービスがUIと別のプロセスで動いているからです。

じゃあどうやって使うのかというとこんな感じで使います。

以下の例ではIRosterListenerを使っていますが他のイベントも基本は同じです。

public class SampleActivity extends Activity {
  private IGTalkSession gtalkSession;
  ServiceConnection conn = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
      try {
        gtalkSession = IGTalkService.Stub.asInterface(service).getDefaultSession();
        gtalkSession.addRemoteRosterListener(rosterListener); 
        gtalkSession.requestRoster(); 
        gtalkSession.setPresence(new Presence(Im.PresenceColumns.AVAILABLE,"ほげほげ"));
      } catch (DeadObjectException ex) { 
        //
      }
    }
    public void onServiceDisconnected(ComponentName className) {
      gtalkSession = null;
    }
  }
  IRosterListerner.Stub rosterListener = new IRosterListerner.Stub() {
    public void presenceChanged(String arg0) throws DeadObjectException {
      runOnUIThread(new Runnable() {
        public void run() {
          Toast.makeText(SampleActivity.this, "presence changed!", Toast.LENGTH_LONG).show();
        }
      }); 
    } 
    public void rosterChanged() throws DeadObjectException { 
      runOnUIThread(new Runnable() {
        public void run() {
          Toast.makeText(SampleActivity.this, "roster changed!", Toast.LENGTH_LONG).show();
        }
      }); 
    }
  }
  public void onCreate(Bundle icicle) {
    setContentView(R.layout.sample);
    …省略
    bindService(new Intent().setComponent(
        GTalkServiceConstants.GTALK_SERVICE_COMPONE), conn, 0); 
  }
}

リスナーインターフェースを直接実装するのじゃなくてStubクラスを使うのがコツです。

またUIに関係する処理を実行するときはActivityクラスのrunOnUIThreadメソッドを使わないとうまく動きません(Handler使っても動きます)。

インナークラス使いまくりで少し汚いコードになってしまうのが欠点ですね。

あと上記実装だとConcurrencyModificationExceptionがかなりの頻度で発生するのでイベントの中でgtalkSessionオブジェクトをロックしたほうがいいです。