java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ...

        项目开发遇到下面这个报错了!

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ..._第1张图片

问题原因

        直接说原因,就是因为进程间不能直接传递对象,应该传递该Binder对象的映射(代理对象),所以类型转换就出错了。如果在同一个进程中,直接传递对象没有关系,下面的类型强转是没有问题的,但是如果是不同进程,强转就会失败,就会报上面的错误。

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ..._第2张图片

        那启动应用内启动service怎么就成进程间通信了呢?因为service是指定了android:process=":remote"。就算自己的service没有指定android:process,如果应用中其他service写了android:process,也会导致自己的service报错。

        我的Service是一个websocket通信服务,本来我把bindService写在Activity中,但是这有一个问题,就是页面跳转,服务会随着声明周期被销毁重建,这样每次跳转页面都重新连接,浪费时间,于是我就把Service挪到了Application里面。我的页面一个LoginActivity,一个MainActivity,页面跳转到MainActivity的时候就报错了,因为我的MainActivity里面使用了百度地图,而百度地图的service如下


        

这样就导致我的Service的binder转换报错了。把百度地图Service里面的android:process=":remote"去掉就就可以了。

解决办法

一.去掉android:process=":remote"
二.aidl方式

        下面记录一下,进程间Service要想解决这个问题,就是需要用aidl方式。

1.创建aidl文件

        Android Studio可以直接创建,在与java文件平级的文件下会创建一个aidl文件夹,里面包名是app的包名,创建一个后缀为.aidl的文件夹

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ..._第3张图片

创建之后是这样的

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ..._第4张图片

aidl文件如下:

// IMyAidlInterface.aidl
package com.deviser.androidremote;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    //这用来传递Service的包名和文件名,传递之后通过反射获取Service对象
    String getName();
}

编译之后,build下面会生成

java.lang.ClassCastException: android.os.BinderProxy cannot be cast to ..._第5张图片

2.重写Service的Binder方法
//    //用于Activity和service通讯
      //这是原来的方法,直接把WebClientService这个对象返回了
//    public class WebClientBinder extends Binder {
//        public WebClientService getService() {
//            return WebClientService.this;
//        }
//    }


    //通过aidl方式,继承IMyAidlInterface.Stub,返回的是WebClientService的包名和文件名
    //进程间传递的是字符串
    public class WebClientBinder extends IMyAidlInterface.Stub{
        @Override
        public String getName() throws RemoteException {
            return WebClientService.class.getName();
        }
    }
3.修改onServiceConnected
    private var webServiceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName?, iBinder: IBinder?) {
              //原来就是这里iBinder强转成WebClientService.WebClientBinder报错
//            var binder: WebClientService.WebClientBinder = iBinder as WebClientService.WebClientBinder
//            webClientService = binder.service

            // 获得代理对象
            var proxy = IMyAidlInterface.Stub.asInterface(iBinder)
            try {
                //通过反射机制,把字符串转换成对象WebClientService对象
                var clazz = Class.forName(proxy.name)
                webClientService = clazz.newInstance() as WebClientService?
            }catch (e: Exception){
                e.printStackTrace()
            }
        }

        override fun onServiceDisconnected(componentName: ComponentName?) {
            Log.e(MyConstant.TAG,"服务与活动成功断开");
        }
    }

到这里,问题就解决啦!

你可能感兴趣的:(android)