2

我试图将 MainActivity 绑定到前台服务,然后得到以下异常,已经搜索了一个多小时,不知道我做错了什么,请救救我。

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.leonard.sg.okcoin.service.SyncAndTradeService$SyncAndTradeBinder
        at com.leonard.sg.okcoin.MainActivity$1.onServiceConnected(MainActivity.java:50)
        at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1101)
        at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1118)
        at android.os.Handler.handleCallback(Handler.java:725)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5227)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
        at dalvik.system.NativeStart.main(Native Method)

我的 MainActivity 中的代码:

private SyncAndTradeService syncAndTradeService;
private boolean hasBounded = false;

private Intent syncAndTradeServiceIntent;

private ServiceConnection syncAndTradeServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        SyncAndTradeService.SyncAndTradeBinder syncAndTradeBinder = (SyncAndTradeService.SyncAndTradeBinder) service;
        syncAndTradeService = syncAndTradeBinder.getSyncAndTradeService();
        hasBounded = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        syncAndTradeService = null;
        hasBounded = false;
    }
};

我试图在 onCreate 方法中做到这一点:

syncAndTradeServiceIntent = new Intent(this, SyncAndTradeService.class);

bindService(syncAndTradeServiceIntent, syncAndTradeServiceConnection, Context.BIND_AUTO_CREATE);

这是我的服务代码:

public class SyncAndTradeService extends Service {

    public static final int MY_FOREGROUND_SERVICE_START_ID = 996539;

    private IBinder syncAndTradeBinder = new SyncAndTradeBinder();

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        startSyncAndTradeService();

        return Service.START_REDELIVER_INTENT;
    }

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

    @Override
    public boolean onUnbind(Intent intent) {
        return false;
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

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

    public class SyncAndTradeBinder extends Binder {

        public SyncAndTradeService getSyncAndTradeService() {
            return SyncAndTradeService.this;
        }

    }

    private void startSyncAndTradeService() {
        startForeground(MY_FOREGROUND_SERVICE_START_ID, buildFixedNotification());
    }

    private Notification buildFixedNotification() {

        Intent notificationIntent = new Intent(this, MainActivity.class);

        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

        Notification notification = new Notification.Builder(this)
            .setContentTitle("OKCoin Robot")
            .setContentText("OKCoin robot is running in background")
            .setSmallIcon(R.drawable.bitcoin)
            .setContentIntent(pendingIntent)
            .build();

        return notification;
    }

}

这是我在 Manifest.xml 中的服务声明

<service
    android:name=".service.SyncAndTradeService"
    android:exported="false"
    android:icon="@drawable/bitcoin"
    android:process=":SyncAndTrade">
</service>
4

1 回答 1

19

等不及了,所以在我一整天空闲的时候一直在研究,幸运地找到了解决方案,希望这对像我这样的初学者有所帮助。

  • 如果您在与您的应用程序相同的进程中运行该服务,这意味着您应该在 Manifest.xml 中声明该服务,而不使用“android:process”,如果您这样做,那么上述绝对可以正常工作。
  • 当您尝试将您的应用程序组件绑定到在不同进程中运行的服务时,将引发上述异常
  • 所以解决方案是用 AIDL 包装你的 IBinder。
  • 以下是基于上述代码的代码

定义你的 AIDL 接口

package com.leonard.sg.okcoin.service.robot.aidl;

interface ISyncAndTradeService {

    boolean startTradeEngine();

}

然后将您的服务中的 onBind 方法更改为:

@Override
public IBinder onBind(Intent intent) {
    return new ISyncAndTradeService.Stub() {

        @Override
        public boolean startTradeEngine() throws RemoteException {
            return false;
        }
    };
}

然后将构建服务连接类细化为:

private ISyncAndTradeService syncAndTradeService;
private boolean hasBounded = false;

private Intent syncAndTradeServiceIntent;

private ServiceConnection syncAndTradeServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        syncAndTradeService = ISyncAndTradeService.Stub.asInterface((IBinder) service);
        hasBounded = true;
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        syncAndTradeService = null;
        hasBounded = false;
    }
};

那么一切都会正常

但这引发了另一个问题,根据服务声明的属性'android:process'的谷歌文档,我们可以这样做:

android:process 运行服务的进程的名称。通常,应用程序的所有组件都在为应用程序创建的默认进程中运行。它与应用程序包同名。元素的 process 属性可以为所有组件设置不同的默认值。但是组件可以使用自己的进程属性覆盖默认值,从而允许您将应用程序分布在多个进程中。如果分配给此属性的名称以冒号 (':') 开头,则会在需要时创建应用程序专用的新进程,并在该进程中运行服务。如果进程名称以小写字符开头,则服务将在该名称的全局进程中运行,前提是它有权这样做。这允许不同应用程序中的组件共享一个进程,

但实际上,如果我声明 'android:process' 以字符开头,无论是小写还是大写,我都会收到此错误:

DEVICE SHELL COMMAND: pm install -r "/data/local/tmp/com.leonard.sg.okcoin"
pkg: /data/local/tmp/com.leonard.sg.okcoin
Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED]

唯一的选择是以 ':' 或 '.' 开头。

于 2015-04-28T09:57:02.307 回答