Woppi
Woppi

Reputation: 5431

How to handle socket events as background service in Android?

I'm new to Android development and I wanted my app to be able to detect socket events even when app is not active via Background service (so I can do push notification e.g if there's a new message triggered by a socket event like how Whatsapp and others do it).

I implemented Background service and an application class that starts the service but stuck where and how to put the socket events as Runnable task in my Background service.

I modified the socket.io android chat project example below and added service and application class.

ChatApplication.java

package com.github.nkzawa.socketio.androidchat;

import android.app.Application;
import android.content.Intent;
import android.content.res.Configuration;

import io.socket.client.IO;
import io.socket.client.Socket;

import java.net.URISyntaxException;

public class ChatApplication extends Application {

    @Override
    // called when the application is starting, before any other application objects have been created
    public void onCreate() {
        super.onCreate();

        // represents our background service
        Intent background = new Intent(this, SocketBackgroundService.class);
        startService(background);
    }

    private Socket mSocket;
    {
        try {
            mSocket = IO.socket(Constants.CHAT_SERVER_URL);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    public Socket getSocket() {
        return mSocket;
    }
}

SocketBackgroundService.java

package com.github.nkzawa.socketio.androidchat;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class SocketBackgroundService extends Service {
    private boolean isRunning;
    private Thread backgroundThread;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        this.isRunning = false;
        this.backgroundThread = new Thread(myTask);
    }

    private Runnable myTask = new Runnable() {
        @Override
        public void run() {
            // do something in here
            Log.i("INFO", "SOCKET BACKGROUND SERVICE IS RUNNING");

            //TODO - how to handle socket events here?
            //How do I do something like mSocket.on(Socket.EVENT_CONNECT,onConnect); here?
        }
    };

    @Override
    public void onDestroy() {
        this.isRunning = false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if( !this.isRunning) {
            this.isRunning = true;
            this.backgroundThread.start();
        }

        return START_STICKY;
    }
}

Upvotes: 15

Views: 20328

Answers (3)

Sharp Dev
Sharp Dev

Reputation: 970

As @Ashish and @Mangesh Sambare both show/state you should have the Web Socket part of the background service, however there are some things you should know before doing such.

  • In reference to the Socket.IO documentation

CAUTION!
Socket.IO is not meant to be used in a background service for mobile applications.

The Socket.IO library keeps an open TCP connection to the server, which may result in a high battery drain for your users. Please use a dedicated messaging platform like FCM for this use case.

If you still insist on not following the suggestion then consider using plain web sockets (again in the background service). This will give you better control over how the socket is kept open, and will still cause battery drain, but should be less than that of Socket.io.

Upvotes: 0

Mangesh Sambare
Mangesh Sambare

Reputation: 614

You open socket on main thread. Do not open socket connections on main thread, it will gives you ANR(application not responding) error which is occur due to lots of heavy work on UI thread. It blocks UI thread for more than 5 sec. So I suggest you to open socket connections on thread inside service.
Here is example using plain socket:

  1. Create one service class for starting thread on background service
  2. Create on Thread class for opening socket connection on thread
  3. create separate class for socket communication

    public class SocketBackgroundService extends Service {
    
    private SocketThread mSocketThread;
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onCreate() {
    
        mSocketThread = SocketThread.getInstance();
    }
    
    
    @Override
    public void onDestroy() {
        //stop thread and socket connection here
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (mSocketThread.startThread) {
        } else {
            stopSelf();
        }
    
        return START_STICKY;
    }
    }
    
    public class SocketThread extends Thread {
    
    private static SocketThread mSocketThread;
    private SocketClient mSocketClient;
    
    private SocketThread() {
    }
    
    // create single instance of socket thread class
    public static SocketThread getInstance() {
        if (mSocketThread == null)//you can use synchronized also
        {
            mSocketThread = new SocketThread();
        }
        return mSocketThread;
    }
    
    
    public boolean startThread() {
          mSocketClient = new SocketClient();
        if (socketClient.isConnected()) {
            mSocketThread.start()
            return true;
        }
        return false;
    }
    
    @Override
    public void run() {
        super.run();
        while (mSocketClient.isConnected()) {
            // continue listen
        }
        // otherwise remove socketClient instance and stop thread
    }
    
    public class SocketClient {
        //write all code here regarding opening, closing sockets
        //create constructor
        public SocketClient() {
            // open socket connection here
        }
    
        public boolean isConnected() {
            return true;
        }
    }
    

Upvotes: 6

Ashish
Ashish

Reputation: 106

If you need the socket to be alive even after your application is stopped. Move your socket to the Background service and then you can add the socket events in the service.

Upvotes: 8

Related Questions