ClassCastException when binding service - android

I am following the tutorial from Bound service : http://developer.android.com/guide/components/bound-services.html and use it in my code. But when I use the code from the tutorial I get an error at this line : service = binder.getService(); cannot convert from localService to IBinder. So as a solution I cast it to IBinder. But I get a classCastException then when I start running the app.
This is the code from the MainActivity :
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
service = (IBinder) binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
The code in my service looks like this :
public class LocalService extends Service implements LocationListener,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
com.google.android.gms.location.LocationListener, SensorEventListener {
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
And my manifest file looks like this :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.geotodo"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- Required for accessing our current location -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<application
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>
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="KEY"/>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<service android:enabled="true" android:name=".LocalService" />
</application>
Please help someone.

Use:
service = (LocalService) binder.getService();
... instead of:
service = (IBinder) binder.getService();
You are calling a Service object and trying to type cast it to a IBinder object it is giving to a ClassCastException.

Related

Android Auto app never calls onGetRoot

I'm developing an audio streaming application for Android and integrating Android Auto. I've been following these two tutorials.
Android Developer Training
PTR Android Blog
Using the Desktop Head Unit, I'm able to select my media app from the media app list, but from there a ProgressBar stays instead of giving way to the "To play something, open the menu at the top left." message seen in the Universal Music Player.
On inspection, it seems that the MediaBrowserServiceCompat's onGetRoot()is never invoked and thus never populating my MediaItemCompat into the Auto app's list.
My manifest contains the following.
<manifest package="com.app.audio"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name="com.app.audio.AudioApp"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name="com.app.audio.presentation.home.HomeActivity"
android:label="#string/app_name"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.app.audio.presentation.weather.WeatherActivity"
android:screenOrientation="userPortrait"/>
<activity android:name="com.app.audio.presentation.settings.SettingsActivity"/>
<activity android:name="com.app.audio.presentation.alarm.AlarmActivity"/>
<activity android:name="com.app.audio.presentation.sleep.SleepActivity"/>
<receiver android:name="com.app.audio.audio.AudioIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
<action android:name="android.media.AUDIO_BECOMING_NOISY"/>
</intent-filter>
</receiver>
<receiver android:name="com.app.audio.presentation.alarm.AlarmReceiver"></receiver>
<receiver android:name="com.app.audio.presentation.sleep.SleepReceiver"></receiver>
<service
android:name="com.app.audio.data.service.media.MediaService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version"/>
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="#xml/automotive_app_desc"/>
<meta-data
android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="#drawable/ic_launcher"/>
</application>
My automotive_app_desc.xml is very simple, only declaring Media.
<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
<uses name="media"/>
</automotiveApp>
My MediaService extends MediaBrowserServiceCompat. In the onCreate() I create and set my MediaSessionCompat.
#Override
public void onCreate() {
super.onCreate();
//...
mediaSession = new MediaSessionCompat(
this,
SESSION_TAG,
mediaIntentReceiver,
null
);
mediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
play(selectedStream);
}
#Override
public void onPause() {
super.onPause();
pause();
}
#Override
public void onStop() {
super.onStop();
stop();
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
playNextStation();
}
#Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
playPreviousStation();
}
});
mediaSession.setActive(true);
setSessionToken(mediaSession.getSessionToken());
updatePlaybackState(ACTION_STOP);
}
Finally, the two overridden methods from MediaBrowserServiceCompat, of which neither is ever called.
#Nullable
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid, #Nullable Bundle rootHints) {
return new BrowserRoot(ROOT_ID, null);
}
#Override
public void onLoadChildren(#NonNull String parentId, #NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
List<MediaBrowserCompat.MediaItem> items = getMediaItemsById(parentId);
if (items != null) {
result.sendResult(items);
}
}
As far as I can tell, that's everything required to get an Android Auto started, yet when I open the app on my desktop head unit, there is only a ProgressBar greeting me, and when I open the off-screen nav drawer, there's another one. I haven't heard of that state in any material I've read. Is there something I missed?
Ultimately, the issue didn't have anything to do with what I described. The aforementioned MediaService also does other tasks that require a custom Binder. This custom Binder didn't call the onGetRoot() needed for the Head Unit. As a solution, I check the Intent action and return super.onBind() when it's from the MediaBrowserServiceCompat.
#Override
public IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction())) {
return super.onBind(intent);
}
return new MediaBinder();
}
The SERVICE_INTERFACE is a constant in MediaBrowserServiceCompat.
I'm developing an Android auto but I have some problems in this part of my code, in Onbind method of the service:
public IBinder onBind(Intent arg0) {
Log.i("TAG", "OnBind");
// TODO Auto-generated method stub
if (SERVICE_INTERFACE.equals(arg0.getAction())) {
Log.i("TAG", "SERVICE_INTERFACE");
registerReceiver(receiver, filter);
return super.onBind(arg0);
} else {
Log.i("Musica Service", "musicBind");
return musicBind;}
}
I have other activities bound with my service through a musicBind IBinder, but on the other hand I have set all things to connect my app in Android auto interface but after close my app after disconnect the device from the android auto I can't stop my mediabrowserservice compat. I think it's due to this SERVICE_INTERFACE keeps binded the service. How can I stop or destroy this from the same servicemediabrowserservicecompat?

bindservice always returning false

I have a project that was working in API 14. Now I am moving to API 21 so I am making the changes I need to.
It is an app that uses location to track a route. I have a service that takes care of the location stuff. But when I try to bind to that service it keeps coming back false and I cant figure out why.
Below is my code. I dont even know how to start looking at this really. What reasons could there be for the Service not binding?
Below is my code:
Service Connection class
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mServiceMessenger = new Messenger(service);
// Now that we have the service messenger, lets send our messenger
Message msg = Message.obtain(null, LOCATION_CHANGED, 0, 0);
msg.replyTo = mClientMessenger;
/*
* In case we would want to send extra data, we could use Bundles:
* Bundle b = new Bundle(); b.putString("key", "hello world");
* msg.setData(b);
*/
try {
mServiceMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mServiceMessenger = null;
mBound = false;
}
};
bindService method call - val is always false
public boolean bindService() {
/*
* Note that this is an implicit Intent that must be defined in the
* Android Manifest.
*/
Intent i = new Intent();
i.setPackage("com.example.conor.routetracker.ACTION_BIND");
boolean val = getBaseContext().getApplicationContext().bindService(i, mConnection,
Context.BIND_AUTO_CREATE);
return val;
}
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/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.example.conor.routetracker.GPSService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.example.conor.routetracker.ACTION_BIND" />
</intent-filter>
</service>
<activity
android:name="com.example.conor.routetracker.ListFiles"
android:label="#string/title_activity_list_files" >
</activity>
</application>
One line change saves the day.
When I create my Intent it should be
Intent i = new Intent(getApplicationContext(), GPSService.class);
public boolean bindService() {
Intent i = new Intent("com.example.conor.routetracker.ACTION_BIND");
i.setPackage("com.example.conor.routetracker")
return getBaseContext().getApplicationContext().bindService(i, mConnection, Context.BIND_AUTO_CREATE);
}

Android service not starting, no idea why

I'm trying to run a thread by starting it with a service, but it won't start. It won't even log.
This is my inner service class. The service class creates a new background thread and starts it.
The backgroundthread and the service class are both innerclasses so they can reach the variables.
public class MyService extends Service {
private BackgroundThread background;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
background = new BackgroundThread();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, startId, startId);
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
background.start();
return startId;
}
}
I'm starting the service in the MainActivity by this:
startService(new Intent(this, MyService.class));
And this is my manifest:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.antioversleepapp.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>
<activity
android:name="com.example.antioversleepapp.SettingsActivity"
android:label="#string/title_activity_settings" >
</activity>
<activity
android:name="com.example.antioversleepapp.InfoActivity"
android:label="#string/title_activity_info" >
</activity>
<service android:enabled="true" android:name="com.example.antioversleepapp.MyService" />
</application>
Please help me out
This is my inner service class
That is not possible. It either needs to be a static inner class (in which case, your <service> element also needs changing) or it needs to be a separate public class.
The backgroundthread and the service class are both innerclasses so they can reach the variables.
I do not see any "variables" that your service needs to "reach". Moreover, it is impossible for Android to create an instance of an inner class, since it does not have an instance of the outer class.
try this code in your start service button, I hope it works :
Intent intent = new Intent(MainActivity.this,Service.class);
MainActivity.this.startService(intent);

Android services method not calling from activity

I have service which include connecting to bluetooth device.I'm calling this service from my first activity. And service successfully created and started . But when i use bind in first activity to call method in service, its not executing. I referred to LocalService example
My service code:
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
public class LocalBinder extends Binder {
public BluetoothServices getService() {
// Return this instance of LocalService so clients can call public methods
return BluetoothServices.this;
}
}
public void SendData(){
Log.d("msg", "Send msg");
}
I'm using below code in my first activity:
BluetoothServices mService;
boolean mBound = false;
#Override
public void onStart(){
super.onStart();
Intent btservices = new Intent(getApplication(),BluetoothServices.class);
startService(btservices);
bindService(btservices, mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(mBound){
mService.SendData();
}
}
What is the problem in above code?Why it is not binding and calling method?
My manifest:
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:debuggable="true"
android:icon="#drawable/logo_50"
android:theme="#style/app_theme" >
<service android:name="com.example.utilities.BluetoothServices"></service>
<activity
android:name="com.example.pkg.Thisisit"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
What is the problem in above code?Why it is not binding and calling method?
Order of operations. The order of lifecycle callbacks when the Activity starts is
onCreate()
onStart()
onResume()
In your code, you check if the Service is bound and call the send data method in onCreate(), but don't bind to the Service until onStart(), so your first block of code will never trigger since you are never bound at that point.
A couple other points to note:
Service binding is asynchronous. Even if you reorder your calls so SendData() were in onResume() the Service would still not likely be ready; the Service is not immediately bound after you call bindService(). That's what ServiceConnection is for, it tells you when the Service is available with the onServiceConnected() callback. You must wait for this before accessing anything.
When binding to a Service, you don't also have to start it. A bound Service is started on binding if it is not already running. In the above code, the call to startService() is superfluous.

Android service bind trouble

Hello community I have the following problem.
My manifest file looks like the following.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.someCo.test"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.wifi" />
<uses-sdk android:minSdkVersion="8" />
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" >
<service android:name = ".BackgroundService" android:exported="true" />
</application>
</manifest>
my Activity's onCreate has the following line of code.
this.context.startService(new Intent(this.context, com.someCo.test.BackgroundService.class));
this.context.bindService(new Intent(this.context, com.someCo.test.BackgroundService.class), serviceConnection, Context.BIND_AUTO_CREATE);
my Activity also has the following private class.
private ServiceConnection serviceConnection = new ServiceConnection() {
public static final String TAG = "Service Connection Class";
public void onServiceConnected(ComponentName className, IBinder service) {
try {
com.someCo.test.BackgroundService.MyBinder binder = (com.someCo.test.BackgroundService.MyBinder)service;
backgroundService = binder.getService();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//backgroundService = ((BackgroundService.MyBinder) service).getService();
//Toast.makeText(context,"service connected", Toast.LENGTH_LONG);
Log.i(TAG, "onServiceConnected");
}
//#Override
public void onServiceDisconnected(ComponentName className) {
backgroundService = null;
}
};
my Service has the following.
private final IBinder binder = new MyBinder();
public class MyBinder extends Binder{
private static final String TAG = "MyBinder";
BackgroundService getService(){
Log.i(TAG, "get service");
return BackgroundService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
Log.i(TAG, "onBind destroyed");
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind destroyed");
return super.onUnbind(intent);
}
At this line I get the exception below the code.
(com.someCo.test.BackgroundService.MyBinder)service;
backgroundService = binder.getService();
java.lang.classCastException: android.os.BinderProxy.
Could someone kindly point me to my mistake, I can't seem to figure it out. Please forgive the very verbose code, as I was trying to be as explicit as possible in debugging this problem.
Thanks,
I don't know why you have written the code for start Service using both way(StartService and BindService)?
Here is the example for the Bind Service. you can refer this blog.
I have tried this thing my self several times. But from my experience, if you just need to bind the service to get some data from the service, there is no need to do so.
Just use localbroadcastmanager. It is sufficient to send the data from the service to application. It is quite easy, safe, less prone to memory leaks.

Categories

Resources