私は、Android用のasmack-Android-7-beemライブラリを使用しています。アプリが動作し続けるなど、バックグラウンドサービスを実行しています。しかし、遅かれ早かれ、XMPP接続は予告なしに終了します。サーバーは、クライアントはまだオンラインですが、パケットの送受信は行われないと言います。
たとえば、他のクライアントに新しいプレゼンスがある場合、クライアントはプレゼンスパケットを受信しません。メインのApplicationクラスの属性としてXMPPConnectionを持っています。
接続が確立される前にConnectionConfiguration config.setReconnectionAllowed(true)
を設定しました。
しかし、再接続は行われません。 XMPPConnection connection.isConnected()
はtrueを返します。
そのため、クライアントは接続が実際に失われたことを認識していません。
接続を維持する方法はありますか?
Asmackを使用する場合、DalvikにReconnectionManagerクラスをロードさせ、静的初期化ブロックを実行させるには、次のようなコードをアプリに追加します。
static {
try {
Class.forName("org.jivesoftware.smack.ReconnectionManager");
} catch (ClassNotFoundException ex) {
// problem loading reconnection manager
}
}
実はリコネクションマネージャーに問題はありません。まず、接続マネージャーに接続リスナーを追加する必要があります。
_connection.addConnectionListener(new ConnectionListener() {
@Override
public void reconnectionSuccessful() {
Log.i("","Successfully reconnected to the XMPP server.");
}
@Override
public void reconnectionFailed(Exception arg0) {
Log.i("","Failed to reconnect to the XMPP server.");
}
@Override
public void reconnectingIn(int seconds) {
Log.i("","Reconnecting in " + seconds + " seconds.");
}
@Override
public void connectionClosedOnError(Exception arg0) {
Log.i("","Connection to XMPP server was lost.");
}
@Override
public void connectionClosed() {
Log.i("","XMPP connection was closed.");
}
});
_
エラーが発生した場合、接続が閉じられると、connectionClosedOnError(Exception arg0)が自動的に呼び出されます
_ public void connectionClosed() {
Log.i("","XMPP connection was closed.");
//You can manually call reconnection code if you want to reconnect on any connection close
}
_
次に、reconnectingin()メソッドが呼び出されることを確認し、再接続を試みます。
これがあなたを助けることを願っています。
以下のコードを使用して接続をチェックしますPingManager pingManager = PingManager.getInstanceFor(connection); pingManager.setPingInterval(5000);
isConnectedメソッドは接続の状態をチェックするための信頼性がないため、接続が処理されたかどうかのping失敗処理用のリスナーを追加します。
pingManager.registerPingFailedListener(PingFailedListener);
モバイルネットワーク接続は非常に大きな問題であるため、ブロードキャストレシーバーを使用してモバイルのネットワーク接続を確認する必要があります。データの再接続時にpingMyServerメソッドを使用して、接続が有効かどうかを確認できます。サーバーからping応答を取得している場合は、接続が有効であることを意味しますそれ以外の場合、pingが失敗すると、接続を手動で再接続できます。
ReconnectionManagerでうまく機能する私のコードは次のとおりです
1)xmpp接続にaddConnectionListener
を追加します
XMPPConnectionListener mConnectionListener = new XMPPConnectionListener(username);
connection.addConnectionListener(mConnectionListener);
2)接続が閉じられた場合、ReconnectionManager
クラスを使用して自動的に再接続します
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
reconnectionManager.enableAutomaticReconnection();
reconnectionManager.setEnabledPerDefault(true);
3)ConnectionListener
はサーバーで再接続、接続、認証されます。サーバーとの接続が正常に認証された場合は、PingManager
およびServerPingWithAlarmManager
クラスも登録します。
public class XMPPConnectionListener implements ConnectionListener {
String username="";
public XMPPConnectionListener(String username){
this.username=username;
}
@Override
public void connected(final XMPPConnection connectionObeject) {
sendPresenceAvailable();
Log.d(TAG, "xmpp Connected()");
connected = true;
}
@Override
public void connectionClosed() {
Log.d(TAG, "xmpp ConnectionCLosed()");
isAuthenticatedPreviouly=false;
connected = false;
loggedin = false;
}
@Override
public void connectionClosedOnError(Exception arg0) {
Log.d(TAG, "xmpp ConnectionClosedOnError() :"+System.currentTimeMillis());
isAuthenticatedPreviouly=false;
connected = false;
loggedin = false;
}
@Override
public void reconnectingIn(int arg0) {
Log.d(TAG, "xmpp reconnectingIn() :"+System.currentTimeMillis());
loggedin = false;
}
@Override
public void reconnectionFailed(Exception arg0) {
Log.d(TAG, "xmpp ReconnectionFailed!");
connected = false;
// chat_created = false;
loggedin = false;
try {
connection.connect();
} catch (SmackException | IOException | XMPPException | InterruptedException exception) {
exception.printStackTrace();
}
}
@Override
public void reconnectionSuccessful() {
Log.d(TAG, "xmpp ReconnectionSuccessful");
connected = true;
sendPresenceAvailable();
loggedin = false;
}
@Override
public void authenticated(XMPPConnection connection2, boolean resumed) {
Log.d(TAG, "xmpp Type Main Authenticated() :" + connection.isAuthenticated());
if(connection.isAuthenticated()) {
ServerPingWithAlarmManager.getInstanceFor(connection).setEnabled(true);
PingManager pingManager = PingManager.getInstanceFor(connection);
pingManager.setPingInterval(10);
try {
pingManager.pingMyServer();
pingManager.pingMyServer(true,10);
pingManager.pingServerIfNecessary();
pingManager.registerPingFailedListener(new PingFailedListener() {
@Override
public void pingFailed() {
Log.d("Ping","pingFailed");
disconnect();
connect();
}
});
registerAllListener();
}
}
私のプログラムがサーバー側のJVMで実行されることを除いて、同じ問題があります。
そもそもsmack 4.0を使用しました。その後、smack 4.1にアップデートしましたが、問題はまだ発生していました。最後に、構成モジュールを見つけました: PingManager
これを使用した後、この状況の発生はドロップダウンされました。
connection = new XMPPTCPConnection(config);
PingManager pingManager = PingManager.getInstanceFor(connection);
pingManager.setPingInterval(300); // seconds
Smack 4.1ではServerPingWithAlarmManager
を使用しています。接続を維持する方法の詳細については ramzandroidブログはこちら をご覧ください。
これらの場合、切断を手動で処理する必要があります。つまり、切断をインターセプトする必要があります。切断が発生したときに接続リスナーに通知されます。
public void connectionClosedOnError(Exception exception)
import Android.util.Log;
import com.dagm8.core.protocols.ConnectionState;
import com.dagm8.core.service.XMPPService;
import com.dagm8.events.ConnectionStateEvent;
import org.greenrobot.eventbus.EventBus;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import Java.io.IOException;
import static com.dagm8.core.protocols.ConnectionState.CONNECTED;
import static com.dagm8.core.protocols.ConnectionState.DISCONNECTED;
import static com.dagm8.core.protocols.ConnectionState.RECONNECTING;
/**
* dagm8-Android
* Created by Bedoy on 8/28/17.
*/
public class ConnectionController implements ConnectionListener {
private String TAG = getClass().getCanonicalName();
private XMPPTCPConnection mConnection;
public void setConnection(XMPPTCPConnection connection) {
mConnection = connection;
}
public void init(XMPPTCPConnection connection) throws InterruptedException, XMPPException, SmackException, IOException {
setConnection(connection);
mConnection.setPacketReplyTimeout(10000);
mConnection.addConnectionListener(this);
mConnection.connect();
}
@Override
public void connected(XMPPConnection connection) {
XMPPService.connectionState = RECONNECTING;
notifyConnectionState(RECONNECTING);
try {
mConnection.login();
} catch (XMPPException | SmackException | IOException | InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "connected()");
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
XMPPService.connectionState = CONNECTED;
notifyConnectionState(CONNECTED);
Log.i(TAG, "authenticated()");
}
@Override
public void connectionClosed() {
XMPPService.connectionState = DISCONNECTED;
notifyConnectionState(DISCONNECTED);
Log.i(TAG, "connectionClosed()");
}
@Override
public void connectionClosedOnError(Exception e) {
XMPPService.connectionState = DISCONNECTED;
notifyConnectionState(DISCONNECTED);
try {
mConnection.connect();
} catch (SmackException | IOException | XMPPException | InterruptedException exception) {
exception.printStackTrace();
}
Log.i(TAG, "connectionClosedOnError()");
}
@Override
public void reconnectingIn(int seconds) {
XMPPService.connectionState = RECONNECTING;
notifyConnectionState(RECONNECTING);
Log.i(TAG, "reconnectingIn()");
}
@Override
public void reconnectionSuccessful() {
XMPPService.connectionState = CONNECTED;
notifyConnectionState(CONNECTED);
Log.i(TAG, "reconnectionSuccessful()");
}
@Override
public void reconnectionFailed(Exception e) {
XMPPService.connectionState = DISCONNECTED;
notifyConnectionState(DISCONNECTED);
Log.i(TAG, "reconnectionFailed()");
}
private void notifyConnectionState(ConnectionState state) {
EventBus.getDefault().post((ConnectionStateEvent) () -> state);
}
public boolean isAuthenticated()
{
return mConnection.isAuthenticated();
}
public void login() {
try {
mConnection.login();
} catch (XMPPException | SmackException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}