Question

My app's structure is made of a service running in the background Listening for push messages and forwards these messages to be inserted in DB, Displayed as Notifications or Sent to Chat Activity if the chat window of the chatter is opened and in the front screen and has a broadcast receiver listening.

the following Image Describes the structure and work-flow of my app's chat (Please follow the alphabetical sequence) enter image description here


And here is my code in the Chat Window Activity:

this.service = new ServiceManager(this, PushService.class,
                new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        // Receive message from service
                        switch (msg.what) {
                        case 10:

                        reloadMessagesInTheChat();
                                                     // Play sound
                        if (mp.isPlaying())
                            mp.stop();
                        mp.start();
                        break;

                    default:
                        showErrorMsssage("Some messages arrived");
                        super.handleMessage(msg);
                        break;
                    }
                }
            });


    this.service.start();

            // Now sending the message (I do it initially to tell the service which user is in the chat now, such that it forwards messages to this receiver, instead of creating notifications)
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            try {
                service.send(Message.obtain(null, 10, user_id, 0));
            } catch (RemoteException e) {
                e.printStackTrace();
                                    // This is just a Toast Message:
                showErrorMsssage("Couldn't send messages to the service");
            }
        }
    }, 1000);

And here is the code from the Service:

First this is the condition that routes the message

if(connectedChatUser != ChatUserInTheReceivedMessage ){
    // Create Notification with Pending Intent to open chat windows with the user
}
else{
      send(Message.obtain(null, 10,  "ID_OF_THE_CHATTER"  , 0));
}

Here's the important part of the service :

    ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
    final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.

    private class IncomingHandler extends Handler { 
// Handler of incoming messages from clients.
        @Override
        public void handleMessage(Message msg) {

            switch (msg.what) {
            case MSG_REGISTER_CLIENT:
                mClients.add(msg.replyTo);
                break;
            case MSG_UNREGISTER_CLIENT:
                mClients.remove(msg.replyTo);
                break;            
            default:
                //super.handleMessage(msg);
                onReceiveMessage(msg);
            }
        }
    }



    private int connectedChatUser = 0;
    private int contactList = 0;


        /*@Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return START_STICKY; // run until explicitly stopped.
        }*/


        @Override
        public IBinder onBind(Intent intent) {
            return mMessenger.getBinder();
        }


    protected void send(Message msg) {
     for (int i=mClients.size()-1; i>=0; i--) {
            try {
               mClients.get(i).send(msg);
            }
            catch (RemoteException e) {
                // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
                mClients.remove(i);
            }
        }       
   }

Here's the Receiver in the Service that receives the ID of the open chat window initially

public void onReceiveMessage(Message msg) {
        if (msg.what == CHAT_USER) {
                // User ID sent from the activity initially
            connectedChatUser = msg.arg1;
        }
            // Other cases aren't important as they cause no problem 

      }

Finally the Service in the Activity is an instance of This Class:

public class ServiceManager {
    private Class<? extends PushService> mServiceClass;
    private Context mActivity;
    private boolean mIsBound;
    private Messenger mService = null;
    private Handler mIncomingHandler = null;
    private final Messenger mMessenger = new Messenger(new IncomingHandler());

    private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            if (mIncomingHandler != null) {
                if(GlobalSettings.dev)Log.i("ServiceHandler", "Incoming message. Passing to handler: "+msg);
                mIncomingHandler.handleMessage(msg);
            }
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            //textStatus.setText("Attached.");
            if(GlobalSettings.dev)Log.i("ServiceHandler", "Attached.");
            try {
                Message msg = Message.obtain(null, AbstractService.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even do anything with it
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
            mService = null;
            //textStatus.setText("Disconnected.");
            if(GlobalSettings.dev)Log.i("ServiceHandler", "Disconnected.");
        }
    };

    public ServiceManager(Context context, Class<? extends PushService> serviceClass, Handler incomingHandler) {
        this.mActivity = context;
        this.mServiceClass = serviceClass;
        this.mIncomingHandler = incomingHandler;

        if (isRunning()) {
            doBindService();
        }
    }

    public void start() {
        doStartService();
        doBindService();
    }

    public void stop() {
        doUnbindService();
        doStopService();        
    }

    /**
     * Use with caution (only in Activity.onDestroy())! 
     */
    public void unbind() {
        doUnbindService();
    }

    public boolean isRunning() {
        ActivityManager manager = (ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE);

        for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (mServiceClass.getName().equals(service.service.getClassName())) {
                return true;
            }
        }

        return false;
    }

    public void send(Message msg) throws RemoteException {
        if (mIsBound) {
            if (mService != null) {
                mService.send(msg);
            }
        }
        else{
            if(GlobalSettings.dev)Log.d("From Activity to service:","Failed as it's not bound");
        }
    }

    private void doStartService() {
        mActivity.startService(new Intent(mActivity, mServiceClass));       
    }

    private void doStopService() {
        mActivity.stopService(new Intent(mActivity, mServiceClass));
    }

    private void doBindService() {
        mActivity.bindService(new Intent(mActivity, mServiceClass), mConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }

    private void doUnbindService() {
        if (mIsBound) {
            // If we have received the service, and hence registered with it, then now is the time to unregister.
            if (mService != null) {
                try {
                    Message msg = Message.obtain(null, AbstractService.MSG_UNREGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    mService.send(msg);
                } catch (RemoteException e) {
                    // There is nothing special we need to do if the service has crashed.
                }
            }

            // Detach our existing connection.
            mActivity.unbindService(mConnection);
            mIsBound = false;
            //textStatus.setText("Unbinding.");
            if(GlobalSettings.dev)Log.i("ServiceHandler", "Unbinding.");
        }
    }
}
Was it helpful?

Solution

Well, without going into too much complication my problem is that When my Activity is paused I had no code to unbind the Service.

I just added the appropriate code to unbind onPause and onDestroy , and bind again onResume,

and that's it

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top