Facundo Barrera
Facundo Barrera

Reputation: 3

Not able to connect with a Service

I'm trying to create a service that handles networking in my app. I followed all the steps in https://developer.android.com/reference/android/app/Service and https://developer.android.com/guide/components/bound-services#Binding, but the activity doesn't seem to connect with the service.

Here is the SocketService, which has the TcpClient object that connects to my server using sockets:

public class SocketService extends Service{

    TcpClient tcpClient = new TcpClient();

    private final IBinder mBinder = new LocalBinder();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        SocketService getService() {
            // Return this instance of LocalService so clients can call public methods
            return SocketService.this;
        }
    }

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

    /*
    * Client methods
    */

    public void connect(MyCallback callback, String ip, int port){
        tcpClient.connect(callback, ip, port);
    }

    public String disconnect(){
        return tcpClient.disconnect();
    }

    public String send(String data){
        return tcpClient.send(data);
    }

    public String recv(){
        return tcpClient.recv();
    }
}

Here is my main activity:

public class MainActivity extends AppCompatActivity {

    SocketService socketService;
    boolean bound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onStart(){
        super.onStart();

        Intent serviceIntent = new Intent(MainActivity.this, SocketService.class);

        if(bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)){
            Toast.makeText(getApplicationContext(), "bound", Toast.LENGTH_LONG);
        }

        if(bound) {
            socketService.connect(this, ip, port);
        } else {
            Toast.makeText(getApplicationContext(), "not bond", Toast.LENGTH_LONG).show();
        }
    }

    /*
    * Service callback
    */
    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                   IBinder service) {
            // We've bound to LocalService, cast the IBinder and get LocalService instance
            Toast.makeText(getApplicationContext(), "ServiceConnection", Toast.LENGTH_LONG);
            socketService = ((SocketService.LocalBinder) service).getService();
            bound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            socketService = null;
            bound = false;
        }
    };
}

And the AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.drrbarrera.home">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".SocketService"
            android:enabled="true"
            android:exported="true">
        </service>
    </application>

</manifest>

As I said before, the MainActivity doesn't seem to connect. "socketService" (in the MainActivity) stays null and "bound" stays false, like if "mConnection" wasn't being executed. Any idea of what might be wrong? Any help is appreciated. Thanks in advance!

Upvotes: 0

Views: 54

Answers (1)

Larry Schiefer
Larry Schiefer

Reputation: 15775

The call to bindService() returns a boolean result telling you whether the bind is successful (really, it means in progress). The operation is asynchronous, even within the same process (which is what your LocalBinder is.)

In other words, the binding is not complete until your ServiceConnection.onServiceConnected() is called back. Once that callback is hit and you get the service binder, then you can call through to the backing service.

A few other notes to help you out:

  • Since your Service is running in the same process as your Activity, the calls are direct and not using binder threads. This will have an effect on your Activity code.
  • Blocking calls should not be main on your main (UI) thread. This means if your Activity code is going to call socketService.connect(), it will need to do it from a background thread. Otherwise, you will get an exception as Android now prevents network I/O on the main thread. Other types of blocking operations can result in an ANR, which will result in your app crashing.
  • If your network I/O is for REST or other HTTP related traffic, look at using Retrofit or Volley as they are highly performant, extensible and deal with network and HTTP related heavy lifting for you.

Upvotes: 1

Related Questions