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.
Related
I referred to all the other StackOverflow posts about this problem and I can't get it to work properly.
My goal is to write an app with no main activity, just a service. You should be able to bind to it from a seperate app and interact with it using AIDL.
I previously had both the service and the activity calling it in the same app and it worked flawlessly. But I need to get it working between two seperate apps.
The onBind() of the service looks like this:
#Nullable
#Override
public IBinder onBind(Intent intent) {
// This binds the bluetooth service itself to the logger service, do this when the logger service itself is bound
Intent serviceIntent = new Intent(this, BluetoothService.class);
intent.setPackage(this.getPackageName());
Log.d(getClass().getName(), "started");
if(bluetoothService == null) {
if (this.bindService(serviceIntent, bluetoothServiceConnection, BIND_AUTO_CREATE)) {
Log.d(getClass().getName(), "returned the service");
return mBinder;
} else {
Log.d(getClass().getName(), "returned null");
return null;
}
} else {
Log.d(getClass().getName(), "returned the service");
return mBinder;
}
}
The service itself binds to another service, but all of the bluetooth stuff works already.
The Manifest of the app with the service looks like this:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<application
android:label="#string/app_name">
<service
android:label="LoggerService"
android:name="io.modum.ble.LoggerService"
android:exported="true">
<intent-filter>
<action android:name="io.modum.ble.LoggerService" />
</intent-filter>
</service>
<service android:name="io.modum.ble.service.BluetoothService" />
</application>
In my activity, I bind to it like this:
Intent intent = new Intent();
ComponentName componentName = new ComponentName("io.modum.modum_ble_service", "io.modum.ble.LoggerService");
intent.setComponent(componentName);
boolean success = getApplicationContext().bindService(intent, new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(getClass().getName(), "Service connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
Log.d(getClass().getName(), String.valueOf(success));
The AIDL files have the exact same package name in both applications.
No exception is called, everything works except onServiceConnected is not called.
bindService() returns true, the service receives the intent and is correctly started, "returned the service" is logged, but onServiceConnected() is never called.
I got it running, what was missing was
intent.setPackage("io.modum.modum_ble_service)
Note that the package name is the name of the app, not the package the service is in. Use the package name displayed in LogCat.
I have been searching for a sample or tutorial to change the Interruptions in Lollipop. But I didn't find any complete one. I saw ideas or hints but not a complete one. With those ideas I have created a NotificationListener which is executed but I get this error:
java.lang.ClassCastException:
android.service.notification.NotificationListenerService$INotificationListenerWrapper cannot be cast to My.App.MyNotificationListenerService
My Manifest:
<service android:name=".MyNotificationListenerService"
android:label="Some text here"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
My MyNotificationListenerService class:
public class MyNotificationListenerService extends NotificationListenerService
{
#Override public void onCreate()
{ super.onCreate();
}
#Override public void onDestroy()
{ super.onDestroy();
}
#Override public IBinder onBind(Intent intent)
{ return super.onBind(intent);
}
}
My activity:
Intent serviceIntent = new Intent(MyActivity.this, MyNotificationListenerService.class);
MyServiceConnection oMyServiceConnection = new MyServiceConnection();
bindService(serviceIntent, oMyServiceConnection, Context.BIND_AUTO_CREATE);
//Now we wait onconnect
class MyServiceConnection implements ServiceConnection
{ #Override public void onServiceConnected(ComponentName name, IBinder binder)
{ MyNotificationListenerService oMyNotificationListenerService= ((MyNotificationListenerService ) binder).getService(); <-- here is where I get the ClassCastException
int iFilter = NotificationListenerService.INTERRUPTION_FILTER_PRIORITY; //Or INTERRUPTION_FILTER_ALL or INTERRUPTION_FILTER_NONE
oMyNotificationListenerService.requestInterruptionFilter(iFilter);
}
#Override public void onServiceDisconnected(ComponentName name)
{
}
}
As seen in the source of NotificationListenerService, NotificationListenerService already implements onBind() and is how the NotificationListenerService communicates with the system.
By overriding onBind() to return your own interface, none of the methods that communicate with the system will work - you should see verbose level log messages along the lines of "Unable to contact notification manager".
You can use other methods for communicating with your service such as LocalBroadcastManager.
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.
I would like to provide a service that can be called by other app. Therefore, I have a service and an aidl. But when I try to have a separate application to bind this service (bindService), it just returns me false which means fail. Here is my code.
PS: context is already the ApplicationContext which obtained by calling getApplicationContext()
Code that try to bind the service
private static ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
sService = XXXService.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName name) {
sService = null;
}
};
private static synchronized XXXService getService(final Context context) {
if (sService != null) {
return sService;
} else {
intent.setClassName(context.getPackageName(), "com.xxx.someservice");
if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
Log.i(TAG, "can bind");
} else {
Log.i(TAG, "can not bind");
}
return sService;
}
}
AndroidManifest
<service android:name="com.xxx.someservice"
android:process=":main"
android:exported="true"/>
This seems basically right. I think the issue is that intent.setClassName(context.getPackageName(), "com.xxx.someservice"); should be intent.setClassName("Your.package.name.with.the.service", "com.xxx.someservice"); . context.getPackageName() returns the current package name, so this would work if you were trying to bind in your own package, but your question makes it seem like you are doing it in a separate package.
Using an action name for service worked for me.
E.g:
<service
android:name="..."
android:process="..." >
<intent-filter>
<action android:name="your-unique-action-name" />
</intent-filter>
</service>
And:
...
bindService(new Intent("your-unique-action-name"), mServiceConnection, BIND_AUTO_CREATE);
I build a simple remote service with aidl file. The service and the activity are in two diferent virtual device. The service isn't reachable with an activity. I think the service doesn't start.
In DDMS view my service doen't appear and LogCat launch an error : unable to start service Intent { cmp = com.michelService.BIND pkg=com.michelService}: not found
THANKS for your help!
My AndroidManifest.xml :
*<?xml *version*="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.michelService"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="13" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<service android:name=".ServiceHello" android:exported="true" >
<intent-filter>
<action android:name="com.michelService.BIND"></action>
</intent-filter>
</service>
</application>
</manifest>*
My activity : CallServiceActivity.java :
public class CallServiceActivity extends Activity {
/** Called when the activity is first created. */
IServiceHello service;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
TextView tv1 = new TextView(this);
Intent intent = new Intent();
intent.setAction("com.michelService.BIND");
intent.setPackage("com.michelService");
startService(intent);
ServiceConnection con = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
service = IServiceHello.Stub.asInterface(binder);
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
service= null;
}
};
bindService(intent, con, Context.BIND_AUTO_CREATE);
try {
tv1.setText(service.sayHello("Michel"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
tv1.setText("" + e);
}
layout.addView(tv1);
setContentView(layout);
}
}
The service and the activity are in two diferent virtual device.
It does not work then. You can use services only on the same device. If you want to communicate with a different device then you have to do that via network.
You probably want to start both on the same.
Remote service means "in a different Process" here. You use AIDL to access the other process. Different Processes are a bit like different devices since they don't share a common environment and the communication between them is also a bit like network communication.