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

每次声明并运行两个服务时,我都会遇到以下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>

我正在启动我的第一个服务 在 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);

    }
}

和第二个服务在 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);
        }

    }

第一服务.java

public class FirstService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

第二服务.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() {
        }
    }
}

堆栈跟踪:

 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)

我已经参考了以下链接来解决问题,即如果我的活动和服务在单独的流程中,那么我们不应该像我所做的那样绑定。

Android service android.os.BinderProxy error

java.lang.ClassCastException: android.os.BinderProxy 不能 cast 到 LocalBinder

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

请帮助我解决这种情况,并建议我一个最好的方法,以便我可以实现相同的场景而不会崩溃。


答案 1

遇到此问题(本地服务返回BinderProxy),想要发布我在尝试调试时找到此页面后发现的内容。作为句子运行的简短版本:启动远程服务会在新进程中创建 Application 类的第二个实例,然后尝试绑定到由原始应用程序实例启动的本地服务,就好像它是本地服务一样,但由于该服务在原始进程中运行,因此它是跨进程绑定的,因此您将获得一个 BinderProxy 而不是预期的 Binder 类。

关于Android服务,有几件事要记住。每个服务都有一个分配的进程,它将在其中运行。如果您未在 Android 清单中分配进程,它将在默认进程(运行应用程序、活动等的进程)中运行。不指定进程名称并不意味着它将在绑定到/从中启动服务的同一进程中运行服务。

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

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

接下来,应用尝试绑定到远程服务。Android 将使用您在 Android 清单中提供的名称创建一个新进程。但是,在创建远程服务之前,它需要创建一个应用程序,以便在其中运行服务。它会在远程进程中创建一个新的 MyApplication 实例并启动该实例。

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

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


答案 2

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

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

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

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

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

  • 因此,我将 SecondService 和 FirstService 都移到了 MainActivity Context 中,从而修复了这个问题。

主要活动.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);

        }
    }

推荐