3
votes

Environment: For uninterrupted delivery of messages from one-to-one/one-to-many devices, I have XMPPService running in the background as STICKY service. To receive messages, I have PacketListener which fires whenever a packet arrives at the device. I am using asmack library for client side implementation and OpenFire as my XMPP server.

public class XMPPService extends Service implements INetworkReceiver {
private XMPPConnection mXmppConnection;
private XMPPMethods xmpp;
private DatabaseHandler db;
private UserDetails user;
private SmackAndroid smack;
private Registrations registrations;
private static final String TAG="XMPPService";

@Override
public IBinder onBind(final Intent intent) {
    return new LocalBinder<XMPPService>(this);
}

@Override
public void onCreate() {
    super.onCreate();
    registrations=new Registrations(getApplicationContext());
    xmpp=XMPPMethodsImpl.getInstance(getApplicationContext());
    db=DatabaseHandler.getInstance(getApplicationContext());
    if(db!=null){
        user=db.getUserDetails();
    }
    createConnection();     
}

public void createConnection()
{
    ConnectionConfiguration connConfig = new ConnectionConfiguration(
            AppConstants.HOST, AppConstants.PORT);
    connConfig.setSASLAuthenticationEnabled(false);
    connConfig.setDebuggerEnabled(true);
    connConfig.setReconnectionAllowed(true);
    connConfig.setSecurityMode(SecurityMode.disabled);
    mXmppConnection = new XMPPConnection(connConfig);


    Thread thread=new Thread(new Runnable() {
        private Handler handler=new Handler();
        @Override
        public void run() {

            try {
                if(mXmppConnection!=null && !mXmppConnection.isConnected()){
                    mXmppConnection.connect();
                    Log.i("XMPPServiceAsync",
                            "Connected to " + mXmppConnection.getHost());
                    xmpp.setConnection(mXmppConnection);
                }
            } catch (XMPPException e) {
                e.printStackTrace();
            }

            //mXmppConnection.addConnectionListener(new XmppConnectionListener());

            handler.post(new Runnable() {

                @Override
                public void run() {
                    try {
                        if(db!=null && user!=null && mXmppConnection!=null && !mXmppConnection.isAuthenticated()){
                            if(user.getUserName()!=null && !user.getUserName().isEmpty()){
                                mXmppConnection.login(user.getUserName(), "Tp@!");
                                xmpp.setPresence(2, mXmppConnection);
                                xmpp.setConnection(mXmppConnection);
                                Log.i("XMPPServiceAsync",
                                        "Logged in as " + mXmppConnection.getUser());

                            }
                        }
                    }catch (IllegalStateException e) {
                        e.printStackTrace();
                    } catch (XMPPException ex) {
                        ex.printStackTrace();
                    }


                    if(mXmppConnection.isConnected()){
                        xmpp.rejoinGroups();
                        registrations.registerMessageListener(mXmppConnection);
                        registrations.registerPacketListener(mXmppConnection);
                        registrations.registerMultiUserInvitationListener(mXmppConnection, db, user);
                        registrations.registerPingListener(mXmppConnection);
                    }

                }
            });
        }
    });

    if (thread.getState() == Thread.State.NEW )
    { 
        Log.i(TAG,"Thread State: "+ thread.getState()+"");
        thread.start(); 
    } 
}

@Override
public int onStartCommand(final Intent intent, final int flags,
        final int startId) {
    //rejoining rooms
    try{
        Log.v("XMPP Connection before rejoining",mXmppConnection+"");
        if(mXmppConnection.isConnected()){
            registrations.registerMessageListener(mXmppConnection);
            registrations.registerPacketListener(mXmppConnection);
            registrations.registerMultiUserInvitationListener(mXmppConnection, db, user);
            registrations.registerPingListener(mXmppConnection);
        }
    }catch(Exception e){
        e.printStackTrace();
    }

    return Service.START_STICKY;
}


@Override
public boolean onUnbind(final Intent intent) {
    return super.onUnbind(intent);

}


@Override
public void onDestroy() {
    super.onDestroy();

}

@Override
public void reEstablishConnection() {
    createConnection();
}

}

Problem: When device remains idle for some time, device disconnects from the XMPP server and connection goes null which is against the specifications of XMPP protocol which states that XMPP server maintains persistent connection with devices until we logout forcefully. Reason behind connection going null is not known. When connection goes null, PacketListener stops working.

What all I have tried:

  1. Implemented sticky service for connecting to server and initializing listeners.
  2. Implemented AlarmManager to check if the service is running in the background. It also checks if the connection is alive and authenticated periodically. (Drains Battery)
  3. Implemented Ping manager according to XMPP specification XEP-0199.

Can someone please look into this.

2
are you able to resolve the issue,am having the same issuekondal
not yet. can you explain exactly what are you experiencing?Subhendu Pratap Singh
Same issue i have registered packet listener in service not listening after few minskondal
I am still looking for the solution. Will share it once i resolve the problem.Subhendu Pratap Singh
okay,any idea how to make it persistent i can try samekondal

2 Answers

1
votes

When device remains idle for some time, device disconnects from the XMPP server and connection goes null

Most likely, your process was terminated. This is perfectly normal.

which is against the specifications of XMPP protocol which states that XMPP server maintains persistent connection with devices until we logout forcefully.

Then no mobile device can comply with the XMPP protocol specifications, as Internet access is not guaranteed and universal. Also, users can get rid of your process whenever the user wants to.

Implemented sticky service for connecting to server and initializing listeners.

This will cause your process, and your service, to be restarted sometime after Android terminates the process. During the window of time between your process being terminated and your process being restarted, you will not be in communication with the XMPP server.

0
votes

What commonsware said. START_STICKY just means that Android is free to kill your service when it needs the resources otherwise. It will restart your service after some time. But you are responsible to reestablish the XMPP connection when it happens.