Android XMPP connection is not persistant - asmack

2019-02-20 15:44发布

问题:

I am developing an Android chat app which uses asmack library. What I observe is that the XMPP connection beocmes disconnected after a particular interval of time. ( This also varies from device to device )

I am runnning the connection code in a separate thread as instructed in the below link

Can't establish a new connection with aSmack 4.0.2

But I get the following exception

D/Reconnection Manager(23105): scheduleReconnect: calling tryToConnect
I/System.out(23105): default ping interval is :10
W/System.err(23105): org.jivesoftware.smack.SmackException$ConnectionException
W/System.err(23105):    at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPConnection.java:436)
W/System.err(23105):    at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:811)
W/System.err(23105):    at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:396)
W/System.err(23105):    at com.connectlinks.service.ChatService.connectToXmppServer(ChatService.java:309)
W/System.err(23105):    at com.connectlinks.service.ChatService.access$0(ChatService.java:291)
W/System.err(23105):    at com.connectlinks.service.ChatService$3.run(ChatService.java:280)
W/System.err(23105):    at android.os.Handler.handleCallback(Handler.java:733)
W/System.err(23105):    at android.os.Handler.dispatchMessage(Handler.java:95)
W/System.err(23105):    at android.os.Looper.loop(Looper.java:136)
W/System.err(23105):    at android.app.ActivityThread.main(ActivityThread.java:5586)
W/System.err(23105):    at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(23105):    at java.lang.reflect.Method.invoke(Method.java:515)
W/System.err(23105):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
W/System.err(23105):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
W/System.err(23105):    at dalvik.system.NativeStart.main(Native Method)

Not sure where I am going wrong. I got to know from many of SO questions that connecting/reconecting in a separate thread works. But not happening for me...

The below is the code blocks which I am using

Below here I initially connect to the XMPP server and all good

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
.......
startXmppThread();
.......
}

the below code block where I am starting the XMPP thread

public void startXmppThread(){
    isConnecting = true;
    SmackAndroid.init(ChatService.this);
    PingManager.setDefaultPingInterval(10);
    SmackConfiguration.setDefaultPacketReplyTimeout(20000);
    if(xmppThread == null){
        xmppThread=new Thread(xmppRunnable,"connection thread");
        xmppThread.start();
    }
}

The XMPP runnable code

Runnable xmppRunnable = new Runnable() {

    @Override
    public void run() {
        Log.d(TAG,"starting now thread :"+Thread.currentThread().getId()+" : "+Thread.currentThread().getName());
        Looper.prepare();
        try{
            connectToXmppServer();
            handler.post(mRunnableConnectionMonitor);
        }catch (Exception e) {
            //handler.removeCallbacks(mRunnableConnectionMonitor);
            Log.d(TAG, "Trying to Reconnect from the run catch exception");
            scheduleReconnect();
            e.printStackTrace();

        }

        xyzz = new Handler(new Handler.Callback() {

            @Override
            public boolean handleMessage(android.os.Message msg) {
                switch (msg.arg1) {
                case 1:
                    Log.d(TAG, "Got Message to connect again");
                    try {
                        connectToXmppServer();
                        handler.post(mRunnableConnectionMonitor);
                    } catch (Exception e) {
                        //handler.removeCallbacks(mRunnableConnectionMonitor);
                        Log.d(TAG,"Trying to reconnect from the handleMessage case 1");
                        scheduleReconnect();
                        e.printStackTrace();
                    }
                    break;

                case 2:
                    Log.d(TAG, "Got Message to disconnect");
                    handler.removeCallbacks(mRunnableConnectionMonitor);
                    try {
                        connection.disconnect();
                        Log.d(TAG, "succesfully disconnected");
                    }catch (Exception e) {
                        Log.d(TAG, "Exception while disconnecting");
                        e.printStackTrace();
                    }
                    break;
                case 3:
                    Log.d(TAG,"Trying to reconnect from the handleMessage case 3");
                    scheduleReconnect();
                    handler.removeCallbacks(mRunnableConnectionMonitor);
                    break;
                default:
                    break;
                }
                return false;
            }
        });
        Looper.loop();
    }
};

The code block which connects to the XMPP server

private void connectToXmppServer() throws Exception {
        if(config ==null)
            config = new ConnectionConfiguration(CHAT_SERVER_IP, 5222,host);
        config.setSecurityMode(SecurityMode.disabled);
        config.setSendPresence(true);
        config.setRosterLoadedAtLogin(false);
        if(connection == null)
            connection = new XMPPTCPConnection(config);


        if(mPingManager == null)
            mPingManager = PingManager.getInstanceFor(connection);
        mPingManager.unregisterPingFailedListener(mPingFailedListener);
        mPingManager.registerPingFailedListener(mPingFailedListener);
        System.out.println("default ping interval is :"+mPingManager.getPingInterval());
        if(!connection.isConnected())
            connection.connect();

        if(!ConnectlinksApp.m_sharedHelper.getChatRegistration()){
            String mobileID = ConnectlinksApp.m_sharedHelper.getMobileID();
            Log.d(TAG, "trying to register with : "+mobileID);
            AccountManager accountManager=AccountManager.getInstance(connection);
            try{
                accountManager.createAccount(mobileID, m_strUserPassword);
                Log.d(TAG, "account created successfully"+mobileID);
            }catch (Exception e) {
                Log.d(TAG, "account already exist"+mobileID);
                e.printStackTrace();
            }
            ConnectlinksApp.m_sharedHelper.setChatRegistration(true);
        }

        if(!connection.isAuthenticated()){
            login();
        }
}

The code block whicj reconnects to the XMPP server

protected void scheduleReconnect() {
    if (mReconnectHandler == null) mReconnectHandler = new Handler();
    mReconnectHandler.removeCallbacks(mReconnectRunnable);
    Log.d("Schedule Reconnect","scheduleReconnect: scheduling reconnect in 10 seconds");
    mReconnectHandler.postDelayed(mReconnectRunnable, 10000);
}

The runnable which reconnects

private final Runnable mReconnectRunnable = new Runnable() {
    @Override
    public void run() {
        Log.d("Reconnection Manager","scheduleReconnect: calling tryToConnect");
        try{                
            connectToXmppServer();
            handler.post(mRunnableConnectionMonitor);
            Log.d(TAG, "This shold be called");
        }catch (Exception e) {
        //  handler.removeCallbacks(mRunnableConnectionMonitor);
            e.printStackTrace();
            scheduleReconnect();
        }
    }
};

I tried all possibilities but not able to arrive at a solution. Could anyone who has faced the same issue can help me please. Thanks for your time to read the long post.

*******************EDIT********************** The exception log is

10-23 19:48:50.866 I/System.out(15248): This is what I am looking for beginning
10-23 19:48:50.876 E/ERROR   (15248): ConnectionException
10-23 19:48:50.876 E/ERROR   (15248): org.jivesoftware.smack.SmackException$ConnectionException

10-23 19:48:50.876 E/ERROR   (15248):   at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPConnection.java:436)

10-23 19:48:50.876 E/ERROR   (15248):   at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:811)

10-23 19:48:50.876 E/ERROR   (15248):   at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:396)

10-23 19:48:50.876 E/ERROR   (15248):   at com.connectlinks.service.ChatService.connectToXmppServer(ChatService.java:314)

10-23 19:48:50.876 E/ERROR   (15248):   at com.connectlinks.service.ChatService.access$0(ChatService.java:293)

10-23 19:48:50.876 E/ERROR   (15248):   at com.connectlinks.service.ChatService$3.run(ChatService.java:281)

10-23 19:48:50.876 E/ERROR   (15248):   at android.os.Handler.handleCallback(Handler.java:733)

10-23 19:48:50.876 E/ERROR   (15248):   at android.os.Handler.dispatchMessage(Handler.java:95)

10-23 19:48:50.876 E/ERROR   (15248):   at android.os.Looper.loop(Looper.java:136)

10-23 19:48:50.876 E/ERROR   (15248):   at android.app.ActivityThread.main(ActivityThread.java:5586)

10-23 19:48:50.876 E/ERROR   (15248):   at java.lang.reflect.Method.invokeNative(Native Method)

10-23 19:48:50.876 E/ERROR   (15248):   at java.lang.reflect.Method.invoke(Method.java:515)

10-23 19:48:50.876 E/ERROR   (15248):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)

10-23 19:48:50.876 E/ERROR   (15248):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)

10-23 19:48:50.876 E/ERROR   (15248):   at dalvik.system.NativeStart.main(Native Method)

10-23 19:48:50.885 E/ERROR   (15248): 54.215.XXX.YYY:5222 Exception: null

10-23 19:48:50.885 I/System.out(15248): This is what I am looking for end

*******************End of Exception Log *****************************

So it basically means it is not able to identify the chat server but it is up and running.

Is there any settings I need to do in Ejabberd server. Quite confused. Pls. help me.

The code which I used to get the exception is

System.out.println("This is what I am looking for beginning");
            Log.e("ERROR", "ConnectionException", e);
            for (int i = 0; i < e.getFailedAddresses().size(); i++) {
                HostAddress element = e.getFailedAddresses().get(i);
                Log.e("ERROR", element.getErrorMessage().toString());
            }
            System.out.println("This is what I am looking for end");

**********************EDIT*************************

Upon further investigation, I got to know that the connectToXmppServer method is in a Runnable.

Runnable xmppRunnable = new Runnable() {    
        @Override
    public void run() {
        .....
        connectToXmppServer();
        .....               
        }
}

So, changed the Runnable to a Thread like this

Thread xmppRunnable = new Thread(){ 

After this, the good news is though I am not able to solve the issue (which is the user goes offline in a few hours) I am getting the exception which states that the exception is NetworkOnMainThreadException

I/System.out(10663): NOT CONNECTED

I/System.out(10663): TRYING TO CONNECT

I/System.out(10663): SSmackThis is what I am looking for beginning

I/System.out(10663): SSmackYour localized messagenull

I/System.out(10663): SSmackYour Messagenull

E/ERROR   (10663): SConnectionException

E/ERROR   (10663): org.jivesoftware.smack.SmackException$ConnectionException

E/ERROR   (10663):  at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPConnection.java:436)

E/ERROR   (10663):  at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:811)

E/ERROR   (10663):  at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:396)

E/ERROR   (10663):  at com.connectlinks.service.ChatService.connectToXmppServer(ChatService.java:326)

E/ERROR   (10663):  at com.connectlinks.service.ChatService.access$0(ChatService.java:293)

E/ERROR   (10663):  at com.connectlinks.service.ChatService$3.run(ChatService.java:281)

E/ERROR   (10663):  at android.os.Handler.handleCallback(Handler.java:733)

E/ERROR   (10663):  at android.os.Handler.dispatchMessage(Handler.java:95)

E/ERROR   (10663):  at android.os.Looper.loop(Looper.java:136)

E/ERROR   (10663):  at android.app.ActivityThread.main(ActivityThread.java:5586)

E/ERROR   (10663):  at java.lang.reflect.Method.invokeNative(Native Method)

E/ERROR   (10663):  at java.lang.reflect.Method.invoke(Method.java:515)

E/ERROR   (10663):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)

E/ERROR   (10663):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)

E/ERROR   (10663):  at dalvik.system.NativeStart.main(Native Method)

I/System.out(10663): MYERRORorg.jivesoftware.smack.SmackException$ConnectionException

I/System.out(10663): SThis is what I am looking for middle

E/SSSERROR(10663): android.os.NetworkOnMainThreadException

I/System.out(10663): SSSERROR android.os.NetworkOnMainThreadException

E/SERROR  (10663): 54.XXX.XXX.XXX:5222 Exception: null

I/System.out(10663): SERROR 54.XXX.XXX.XXX:5222 Exception: null

I/System.out(10663): SThis is what I am looking for end

Not sure why I am getting this exception though I am running it in a seperate thread. Any pointers would be very useful to me. I hope this SO question will benefit everyone facing the issue.

回答1:

After a long struggle, here are my observations and I was able to find a solution to the issue. Any feedback about my solution is welcome

The Edit holds the answer.

I simply modified the code from Runnable to a Thread

When the code which connects to the chat server was in a Runnable, I got a android.os.NetworkOnMainThreadException. For some reason, I am not able to find the stack trace of NetworkOnMainThreadException. The ConnectionConfiguration was carrying the NetworkOnMainThreadException when the connection is made using a Runnable.

Hope this helps someone who face a similar issue to mine. I sincerely thank @Flow for his effort in helping me resolve this issue. Your smack work is very commendable and a blessing for the android community.

See the image attached for the exception.



回答2:

It will be better to use AsyncTask for connection in your code rather than using Thread.It is not recommended to use Thread in Android.Try AsyncTask, it is used for all connection related purposes.

class ConnectServer extends AsyncTask<Void, Void, XMPPConnection> {

}