Android:绑定到远程服务

pfp*_*pfp 4 android android-service android-service-binding

我正在构建一个远程服务和一个客户端应用程序,目标是在Nexus 6P设备上执行的API 24.我有一个远程服务,在启动时自动启动.以下是代码片段:

远程服务清单

<?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>
Run Code Online (Sandbox Code Playgroud)

远程服务

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

远程广播接收器

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

远程活动 (Android Studio坚持存在活动)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个单独的项目来在尝试绑定到远程服务的不同包中实现客户端活动.以下是代码片段:

客户端清单

<?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>
Run Code Online (Sandbox Code Playgroud)

客户活动

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

"isServiceRunning"函数返回true,因此我知道abcMyService正在运行.bindService函数似乎成功(在Logcat中没有错误)但是从不执行onServiceConnected回调.

如何从Android目标SDK 24中的xyzClientActivity绑定到abcMyservice?

谢谢!

Dav*_*ser 5

我在这里看到至少2个问题:

1)您Intent在调用中使用"隐式" bindService()(即:您没有明确指定组件).如果您的目标是API 21或更高版本,则应该抛出异常.您应该使用"显式" Intent(即:指定包的名称和类名Service).

2)你的Service回报率null从onBind().这意味着客户端将无法绑定到Service,因为您没有返回IBinder客户端可以用来调用服务上的方法的客户端Service. Try to find a how-to or some example code for how to use bound.

  • 一个“更明确的”`Intent` 将是`intent.setClassName("abc", "abcMyService");`。在这种情况下,您明确说明要实例化的确切组件(类)。如果你这样做,你不需要在 `Intent` 中指定 ACTION,你可以从你的 `&lt;service&gt;` 声明中删除 `&lt;intent-filter&gt;`,因为它不再需要(`&lt; intent-filter&gt;` 仅用于隐式 `Intent` 解析。但是,如果删除 `&lt;intent-filter&gt;`,则需要将 `android:exported="true"` 添加到 `&lt;service&gt;`声明因为没有`&lt;intent-filter&gt;` ... (3认同)
  • ... `Service` 将是私有的,不能用于包“abc”之外的应用程序。如果你提供了一个 `&lt;intent-filter&gt;`,`android:exported` 的默认值自动为 `true`,但如果你不提供 `&lt;intent-filter&gt;`,默认值为 `false`。我希望这很清楚。 (2认同)