每次我声明并运行两个服务时,获取java.lang.ClassCastException:android.os.BinderProxy

Pra*_*oop 12 java android android-service android-service-binding

每次声明并运行两个服务时,我都会遇到以下binder.proxy异常.一个服务在不同的进程(专用于应用程序)中运行,另一个服务在与我的应用程序在(默认应用程序进程)中运行的同一进程中运行,具有Binder实现.

AndroidManifest.xml中:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.service.check"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <application
        android:name="com.service.check.MainApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

         <service
            android:name="com.service.check.SecondService"
            android:exported="false"/>

        <service
            android:name="com.service.check.FirstService"
            android:process=":newProcess" >
        </service>
    </application>

</manifest>
Run Code Online (Sandbox Code Playgroud)

我在按钮上的MainActivity中启动我的第一个服务,点击:

MainActivity.java

public class MainActivity extends ActionBarActivity implements OnClickListener {

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

        mLanchServiceBtn=(Button) findViewById(R.id.launch_btn);

        mLanchServiceBtn.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
       //Starting first service
        Intent launch=new Intent(this,FirstService.class);
        startService(launch);

    }
}
Run Code Online (Sandbox Code Playgroud)

而MainApplication类中的第二个服务为.

MainApplication.java

    public class MainApplication extends Application {

        private SecondService.LocalBinder mBinder;
        private ServiceConnection mConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName className, IBinder service) {
                mBinder = (LocalBinder) service;
            }

            @Override
            public void onServiceDisconnected(ComponentName arg0) {
            }
        };

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

            //starting second service               
            Intent launch=new Intent(this,SecondService.class);
            startService(launch);

            //Binding to it 
            bindService(launch, mConnection, BIND_AUTO_CREATE);
        }

    }
Run Code Online (Sandbox Code Playgroud)

FirstService.java

public class FirstService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

SecondService.java

public class SecondService extends Service{

    //Service Containing Local Binder
    private LocalBinder mBinder=new LocalBinder();
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    class LocalBinder extends Binder{

        public LocalBinder() {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

 02-05 10:32:25.035: E/AndroidRuntime(1424): Process:

 com.service.check:newProcess, PID: 1424 02-05 10:32:25.035:
 E/AndroidRuntime(1424): java.lang.ClassCastException:
 android.os.BinderProxy cannot be cast to
 com.service.check.SecondService$LocalBinder 02-05 10:32:25.035:
 E/AndroidRuntime(1424):    at
 com.service.check.MainApplication$1.onServiceConnected(MainApplication.java:23)
 02-05 10:32:25.035: E/AndroidRuntime(1424):    at
 android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1101)
Run Code Online (Sandbox Code Playgroud)

我已经提到了以下链接来解决这个问题,如果我的活动和服务是在不同的流程中,那么我们就不应该像我所做的那样绑定.

Android服务android.os.BinderProxy错误

java.lang.ClassCastException:android.os.BinderProxy无法强制转换为LocalBinder

但就我而言: 我从MainApplication绑定到SecondService,并且两者都在同一个进程中运行(即默认应用程序进程).我仍然在SecondService中遇到 binderProxy异常,而我的FirstService在单独的进程中运行,我甚至没有绑定到它.

请帮助我解决这种情况,并建议我一个最好的方法,以便我可以实现相同的方案,没有任何崩溃.

Coe*_*ect 23

进入这个问题(返回BinderProxy的本地服务),想要发布我在尝试调试时找到此页面后发现的内容.作为句子运行的短版本:启动远程服务在新进程中创建Application类的第二个实例,然后尝试绑定到原始Application实例启动的本地服务,就像它是本地服务一样因为服务在原始进程中运行,所以它跨进程绑定,你得到一个BinderProxy而不是你期望的Binder类.

有关Android服务的一些事项需要牢记.每个服务都有一个它将运行的已分配流程.如果您没有在Android Manifest中分配流程,它将在默认流程(运行应用程序,活动等的流程)中运行.不提供进程名称并不意味着它将在您绑定/启动服务的同一进程中运行服务.

假设我有一个MyApplication类,它尝试在启动时绑定到两个服务:一个在默认进程中运行的服务(我们将其称为LocalService),一个在单独的进程中运行(RemoteService).

用户启动我的应用程序,在默认进程中创建MyApplication实例.然后,此实例尝试绑定到LocalService.Android在默认进程中创建LocalService,并将LocalService的Binder类返回给app(mBinder = (LocalBinder) service;).这一切都很好,我们已成功绑定到LocalService.

接下来,应用程序尝试绑定到RemoteService.Android使用您在Android Manifest中提供的名称创建一个新进程.但是,在它可以创建RemoteService之前,它需要为要运行的服务创建一个Application.它在远程进程中创建一个新的MyApplication实例并启动它.

但是,在单独进程中运行的新MyApplication实例尝试在启动期间绑定到LocalService.由于LocalService在默认进程中运行,因此这是一个跨进程绑定,但MyApplication希望这是一个进程内绑定.Android返回BinderProxy,第二个MyApplication实例尝试将其强制转换为LocalBinder并崩溃.有趣的是,它会在不同的进程中崩溃,因此您的应用和活动实际上可以继续运行.你将永远无法绑定到远程服务.

如果要使用应用程序上下文绑定到本地服务并使用远程服务,则需要处理Android在启动远程服务时在远程进程中创建另一个应用程序的事实.我没有费心去尝试这个(我只是让我的远程服务成为本地服务),但你可以在创建应用程序期间检查进程名称,如果它不是默认进程则不绑定.


Pra*_*oop 7

做了一些研究和调试后找到答案,

如果我们创建任何服务并将其绑定到MainApplication类(然后服务绑定到整个ApplicationContext或BaseContext),并且如果同一个应用程序包含绑定到Activity特定上下文的其他服务,

//Declared in MainApplication
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
                mBinder = (LocalBinder) service;
     }
Run Code Online (Sandbox Code Playgroud)

在OnServiceConnected()中,我们将为两个服务获取binder对象(在MainApplication中启动SecondService(使用BaseContext注册将获取本地binderObject)类,并且FirstService启动MainActivity(将获得android.os.binderProxyObject,从而导致ClassCastException).

  • 因此,要解决此问题,必须从任何活动上下文启动所有应用程序服务,而不是使用任何全局应用程序上下文.此问题也与 进程无关

  • 因此,我将SecondService和FirstService都移动到MainActivity Context中,从而解决了这个问题.

MainActivity.java

    private Button mLanchServiceBtn;
    private SecondService.LocalBinder mBinder;
    private ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName className, IBinder service) {
                mBinder = (LocalBinder) service;
            }
            @Override
            public void onServiceDisconnected(ComponentName arg0) {
            }
     };
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mLanchServiceBtn=(Button) findViewById(R.id.launch_btn);

            mLanchServiceBtn.setOnClickListener(this);



            //starting second service in activity

            Intent launch=new Intent(this,SecondService.class);
            startService(launch);

            //Binding to it 
            bindService(launch, mConnection, BIND_AUTO_CREATE);
        }


        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }


        @Override
        public void onClick(View v) {

           //Starting FirstService also from MainActivity
            Intent launch=new Intent(this,FirstService.class);
            startService(launch);

        }
    }
Run Code Online (Sandbox Code Playgroud)