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在启动远程服务时在远程进程中创建另一个应用程序的事实.我没有费心去尝试这个(我只是让我的远程服务成为本地服务),但你可以在创建应用程序期间检查进程名称,如果它不是默认进程则不绑定.
做了一些研究和调试后找到答案,
如果我们创建任何服务并将其绑定到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)
| 归档时间: |
|
| 查看次数: |
8513 次 |
| 最近记录: |