Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Binding to a remote service

I'm building a remote service and a client application targetted at API 24 executing on a Nexus 6P device. I have a remote service that automatically starts at boot. Here are the code fragments:

Remote Service Manifest

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

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <service android:name=".MyService" >
            <intent-filter>
                <action android:name="a.b.c.MY_INTENT" />
            </intent-filter>
        </service>

        <activity android:name=".MyActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

Remote Service

package a.b.c;

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

public class MyService extends Service
{
    @Override
    public IBinder onBind(Intent intent) {
        return null;
        // EDIT: see StackOverflow answers/comments below:
        // Returning an IBinder here solves the problem.
        // e.g. "return myMessenger.getBinder()" where myMessenger
        // is an instance of Android's Messenger class.
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }
}

Remote Broadcast Receiver

package a.b.c;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            Intent serviceIntent = new Intent(context, MyService.class);
            context.startService(serviceIntent);
        }
    }
}

Remote Activity (Android Studio insists on there being an Activity)

package a.b.c;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);
    }
}

I then have a separate project to implement a client activity in a different package that attempts to bind to the remote service. Here are the code fragments:

Client Manifest

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

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

</manifest>

Client Activity

package x.y.z;

import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class ClientActivity extends AppCompatActivity
{
    private final String TAG = "ClientActivity";

    private ServiceConnection mMyServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "ServiceConnection onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "ServiceConnection onServiceDisconnected");
        }
    };

    private boolean isServiceRunning(String className) {
        ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo serviceInfo : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (className.equals(serviceInfo.service.getClassName())) {
                return true;
            }
        }
        return false;
    }

    private void bindMyService() {
        Intent intent = new Intent("a.b.c.MY_INTENT");
        intent.setPackage("a.b.c");
        bindService(intent, mMyServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);
        if (isServiceRunning("a.b.c.MyService")) {
            bindMyService();
        }
        else {
            Log.e(TAG, "Service is not running");
        }
    }
}

The "isServiceRunning" function returns true so I know that a.b.c.MyService is running. The bindService function seems to succeed (no errors in Logcat) but the onServiceConnected callback is never executed.

How do I bind to a.b.c.Myservice from x.y.z.ClientActivity in Android target SDK 24?

Thanks!

like image 608
pfp Avatar asked Sep 27 '16 15:09

pfp


People also ask

What does it mean to bind a service android?

The basics. A bound service is an implementation of the Service class that allows other applications to bind to it and interact with it. To provide binding for a service, you must implement the onBind() callback method.

What is unbound service in Android?

Unbound Service or StartedA service is started when an application component, such as an activity, starts it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed.

Which method is used to bind the service?

To provide binding for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming interface that clients can use to interact with the service.

How do you unbind a service?

To unbind a service, use the unbind lb vserver command instead of bind lb vserver .


1 Answers

I see at least 2 problems here:

  1. You are using an "implicit" Intent in the call to bindService() (ie: you haven't specified the component explicitly). This should throw an exception if you are targeting API 21 or higher. You should use an "explicit" Intent (ie: specify the package name and class name of the Service).

  2. Your Service returns null from onBind(). This means that clients will not be able to bind to the Service, because you aren't returning an IBinder that the client can then use to call methods on the Service. Try to find a how-to or some example code for how to use bound Services.

like image 50
David Wasser Avatar answered Oct 10 '22 23:10

David Wasser