How to keep the android client connected to the server even on activity changes and send data to server?
Asked Answered
P

2

22

I initially implemented an async task in my activity which sends data to the server. But when i changed activities the connection was lost. To avoid this my approach was to implement a service that centralizes the network operation and sends data to the server and the code for this service is given below

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

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

public class SocketService extends Service {
  public static final String SERVERIP = ""; //your computer IP address should be written here
  public static final int SERVERPORT = 5000;
  PrintWriter out;
  Socket socket;
  InetAddress serverAddr;

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    System.out.println("I am in Ibinder onBind method");
      return myBinder;
}

  private final IBinder myBinder = new LocalBinder();
  TCPClient mTcpClient = new TCPClient();

  public class LocalBinder extends Binder {
        public SocketService getService() {
            System.out.println("I am in Localbinder ");
            return SocketService.this;

        }
    }

  @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("I am in on create");     
    }

  public void IsBoundable(){
        Toast.makeText(this,"I bind like butter", Toast.LENGTH_LONG).show();
    }

  public void sendMessage(String message){
        if (out != null && !out.checkError()) {
            System.out.println("in sendMessage"+message);
            out.println(message);
            out.flush();
        }
    }

    @Override
    public int onStartCommand(Intent intent,int flags, int startId){
        super.onStartCommand(intent, flags, startId);
        System.out.println("I am in on start");
      //  Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
        Runnable connect = new connectSocket();
        new Thread(connect).start();
        return START_STICKY;
    }


    class connectSocket implements Runnable {

        @Override
        public void run() {


            try { 
                 //here you must put your computer's IP address.
                serverAddr = InetAddress.getByName(SERVERIP);
                Log.e("TCP Client", "C: Connecting...");
                //create a socket to make the connection with the server

                socket = new Socket(serverAddr, SERVERPORT);

                 try {


                     //send the message to the server
                     out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);


                     Log.e("TCP Client", "C: Sent.");

                     Log.e("TCP Client", "C: Done.");


                    } 
                 catch (Exception e) {

                     Log.e("TCP", "S: Error", e);

                 }
            } catch (Exception e) {

                Log.e("TCP", "C: Error", e);

            }

        }

    }


    @Override
    public void onDestroy() {
        super.onDestroy();
          try {
              socket.close();
          } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          socket = null;
      }


    }

Rotator.java is my activity which I bind to this service. Following are few pieces of code from my activity.

private ServiceConnection mConnection = new ServiceConnection() {
            //EDITED PART
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // TODO Auto-generated method stub
         mBoundService = ((SocketService.LocalBinder)service).getService();

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // TODO Auto-generated method stub
         mBoundService = null;
    }

  };


   private void doBindService() {
       bindService(new Intent(Rotator.this, SocketService.class), mConnection, Context.BIND_AUTO_CREATE);
       mIsBound = true;
       if(mBoundService!=null){
       mBoundService.IsBoundable();
       }
   }


   private void doUnbindService() {
       if (mIsBound) {
           // Detach our existing connection.
           unbindService(mConnection);
           mIsBound = false;
       }
   }

@Override
public void onCreate(Bundle savedInstanceState)
{
      super.onCreate(savedInstanceState);
      gestureDetector = new GestureDetector(this, new GestureListener());
      setContentView(R.layout.activity_rotator);


      //Binding the activity to the service to perform client-server operations
      //start service on create
        startService(new Intent(Rotator.this,SocketService.class));
        doBindService();
                  ...........
                  ...........
}   


@Override
protected void onDestroy() {
    super.onDestroy();
    doUnbindService();
}

Now as this service runs in the background, If i want to send some data to the server i use the following

 if(mBoundService!=null)
{
    mBoundService.sendMessage("right");
}
Pharyngoscope answered 20/2, 2013 at 17:5 Comment(0)
P
8

The code is right. The only mistake was that I was trying to start the service twice once in onServiceConnected() method and the other in onCreate() method.

I changed my code to start the service only in onCreate() method in the launcher activity. The rest of the activities directly bind to the service by using doBindService() method

Pharyngoscope answered 22/2, 2013 at 16:6 Comment(4)
you just saved my time.Dixie
your above code is perfect or you have started service twice in above code? you changed above code? I can see you started one time using startservice method and one time using doBindservice method. Please make correct. I a connfuse after reading thisPerhaps
@Perhaps I have used startService method only at the mainactivity which starts the service. The rest of the activities just use doBindService() method in onCreate. The code above is edited with the correct code. I do not understand your confusionPharyngoscope
+1 Even after so many years, your code saved me. To give my 2 cents, technically the service isn't bound before onServiceConnected gets called, that's why i wouldn't set mIsBound = true before that. Apart from that it works perfectlyUmbrian
A
2

When a service is bound to an Activity , it gets killed when the Activity is stopped, its like a background service only for the Activity. Hence, to keep it running, implement the onStartCommand() method in your Service class and return this.START_STICKY. and manage you're service in this method.

Albite answered 20/2, 2013 at 17:54 Comment(4)
I have already done that in my service code. But I do not know how to send the data to the async task to send it to the server.Pharyngoscope
In the activity mTcpClient is always null.Pharyngoscope
No, check the android documentation of a Service , if you're binding it to the Activity using a Binder then it is automatically closed. try removing it from a Binder and instead try it out in onStartCommand(). That is what i am telling you.Albite
@Albite you can both bind and start a service, so it's not getting killed when activity changesCahoot

© 2022 - 2024 — McMap. All rights reserved.