First question here, but I've been around for a while.
What do I have:
I'm building an Android app which plays audio streams and online playlists. Everything is working fine now, but I'm having issues in communicating with my service.
The music is playing in a Service, started with startForeground, so it doesn't gets killed.
I need to communicate from my activity with the service, for getting the track name, image, and a couple of things more.
Whats my issue:
I think I need to start my service with bindService (instead of my current startService) so the activity can talk to it.
However, when I do that, my service gets killed after closing the Activity.
How can I get both? Binding and foreground service?
Thanks!
No. bindService will not start a service . It will just bind to the Service with a service connection, so that you will have the instance of the service to access/control it.
As per your requirement I hope you will have the instance of MediaPlayer in service . You can also start the service from Activity and then bind it. If the service is already running onStartCommand() will be called, and you can check if MediaPlayer instance is not null then simply return START_STICKY.
Change you Activity like this..
public class MainActivity extends ActionBarActivity {
CustomService customService = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// start the service, even if already running no problem.
startService(new Intent(this, CustomService.class));
// bind to the service.
bindService(new Intent(this,
CustomService.class), mConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
customService = ((CustomService.LocalBinder) iBinder).getInstance();
// now you have the instance of service.
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
customService = null;
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (customService != null) {
// Detach the service connection.
unbindService(mConnection);
}
}
}
I have similar application with MediaPlayer service. let me know if this approach doesn't help you.
Quoting Android documentation:
A bound service is destroyed once all clients unbind, unless the service was also started
And about the difference between started and bound just take a look to https://developer.android.com/guide/components/services.html
So, you have to create the Service using startService and then bindService, like #Libin does in his/her example. Then, the service will run until you use stopService or stopSelf or until Android decides that it needs resources and kills you.
Related
I have a bound service that in turn binds multiple services using the same ServiceConnection object. In the onServiceConnected I save the ComponentName and the Binder of each service inside a Map, so that I can use them individually. At a certain point I'd like to unbind some of these services separately. Is there a way to do this in Android?
The only way I was able to find out to unbind a service is to use unbindService(ServiceConnection), but I don't think that I can unbind a specific service using that.
Why this seems to be not supported? Are there any downsides?
Despite the time elapsed by the library and for offering support to lower versions in Android, it works correctly, I am also using services nested in a main one and the connections work or go through the main one. They are multiple Good note that when you start a connection via intent you must close it In the same way, it creates problems in the management of processes when the service is reused by other processes within the application. When closing the connection and instantiating a new one, it creates a small error in the process that was not terminated correctly.
Just to mention how it is currently done! happy code!
here is sample code to bind and unbind service
i = new Intent(this, YourService.class)
protected ServiceConnection mServerConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
mContext.bindService(i, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(i);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
I've got a service that's bound to from a couple of activities, each using a ServiceConnection.
Each activity needs to check before calling the service whether the service is already in use. So in the service I have a function (let's say getCurrentId() ) which returns details of what the service is currently doing.
Then in the client activity, the service connection is set up:
private MyService mService = null;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
MyService.MyBinder myBinder = (MyService.MyBinder) binder;
mService = myBinder.getService();
activeId = mService.getCurrentId();
log.i(TAG, "Service bound" );
}
public void onServiceDisconnected(ComponentName className) {
log.i(TAG, "Service has been killed");
mService = null;
}
};
A button toggles binding to the service:
activity.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
and unbinding:
activity.unbindService(mConnection);
I'm not calling startService() at all.
Before I bind to the service, I check if it's already active and what it's doing:
if (mService == null)
activeId = -1;
else
activeId = mService.getCurrentId();
The problem is, if an activity binds to and then unbinds from the service, the service onDestroy() method is called (I've logging in it to confirm this), which is fine.
BUT this doesn't trigger onServiceDisconnected().
So mService is never set to null, and when I get to that if statement, it happily carries on and calls getCurrentId(), which returns whatever the previous details were.
I gather that onServiceDisconnected() is only supposed to be called when the thread the service is running in is unexpectedly killed, so it's correct that it's not called when the service is destroyed due to the last activity using it unbinding.
As far as I can tell, the service isn't being reinstantiated, I've got logging throughout it.
Which gives me two questions:
Is there an alternative callback function or some way where a ServiceConnection is notified that its service has been destroyed by unbinding?
If the service has been destroyed, then how can I still call its functions? Or is something else going on - is the ServiceConnection or the Binder somehow returning the value without actually calling the service?
onServiceDisconnected() is only called
when a connection to the Service has been lost. This typically happens
when the process hosting the service has crashed or been killed.
Quoted from the Android docs. This seems to be a very rare case, and will not be called when simply unbinding normally from a service.
To keep my connections with a service sane, I would suggest you bind to the service in the Activities onResume method and unbind from it in the onPause method.
I'm trying to make a music player. To do that I'm creating a service that manages a MediaPlayer object and plays the songs. But every time I reopen my music application it starts a new Service and keeps playing two songs simultaneously. How can I make my Activity bind to the already running service?
I noticed that when I don't call unbindService (...) in the OnStop() method my application runs OK. But I don't know if its right to not unbind when the activity stops.
I'm binding like that:
#Override
protected void onStart() {
super.onStart();
Intent service = new Intent(this,MyService.class);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if(mBound) {
unbindService(mConnection);
mBound = false;
}
}
You need to check on onStart() that is service running or not. If service is already running, then you need to just bind it. But in your current code you creating service everytime.
You should try to use Service.START_STICKY for checking that service is already running or not. You can see :
Service
, start Sticky or start not sticky
I think it will help you to update your service class.
I could fix it add startService(...) to the OnStart( ) method. I didnt understand why this fixed, but seems that I need to do that. If anyone knows why please add. Thanks for everyone help.
this is how OnStart got:
#Override
protected void onStart() {
super.onStart();
Intent service = new Intent(this,MyService.class);
bindService(service, mConnection, Context.BIND_AUTO_CREATE);
startService(service);
}
I'm not good in English, but I would try to explain my problem in good way.
So, the problem is:
1) I have a local service
2) I start it and then bound to it.
3) Problem appears when I am about to close that service. onServiceDisconnected method from my implementation of class ServiceConnection is never called. If I close it manually (from settings), or by unbindService, or by stopService, or by combination of unbindService and stopService - onServiceDisconnected still doesn't to be called.
What am I doing wrong?
Short code is below:
protected ServiceConnection mServerConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(LOG_TAG, "onServiceConnected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(LOG_TAG, "onServiceDisconnected");
}
}
public void start() {
// mContext is defined upper in code, I think it is not necessary to explain what is it
mContext.bindService(i, mServerConn, Context.BIND_AUTO_CREATE);
mContext.startService(i);
}
public void stop() {
mContext.stopService(new Intent(mContext, ServiceRemote.class));
mContext.unbindService(mServerConn);
}
I'm testing this code under emulator of Android 2.2
onServiceDisconnected is only called in extreme situations (crashed / killed).
which is very unlikely to happen for a local service since all your application components normally run in the same process... meaning, unless you intentionnaly unbind or destroy the service, it should remain connected, or die with the component using it.
Android developer documentation says...
public abstract void onServiceDisconnected (ComponentName name)
Called when a connection to the Service has been lost. This typically happens when the process hosting the service has crashed or been killed. This does not remove the ServiceConnection itself -- this binding to the service will remain active, and you will receive a call to onServiceConnected(ComponentName, IBinder) when the Service is next running.
For more: https://developer.android.com/reference/android/content/ServiceConnection#onServiceDisconnected(android.content.ComponentName)
I used Context.BIND_AUTO_CREATE in bindService. I have fetch same issue after apply its working perfect for me.
bindService(new Intent(this,XMPPService.class),mConnection, Context.BIND_AUTO_CREATE);
I start a service in an activity then I want the service to stop itself after a while.
I called stopSelf() in the service but it doesn't work.
How to make the service stop itself?
By saying "doesn't work", I guess you mean that the onDestroy()-method of the service is not invoked.
I had the same problem, because I bound some ServiceConnection to the Service itself using the flag BIND_AUTO_CREATE.
This causes the service to be kept alive until every connection is unbound.
Once I change to use no flag (zero), I had no problem killing the service by itself (stopSelf()).
Example code:
final Context appContext = context.getApplicationContext();
final Intent intent = new Intent(appContext, MusicService.class);
appContext.startService(intent);
ServiceConnection connection = new ServiceConnection() {
// ...
};
appContext.bindService(intent, connection, 0);
Killing the service (not process):
this.stopSelf();
Hope that helped.
By calling stopSelf(), the service stops.
Please make sure that no thread is running in the background which makes you feel that the service hasn't stopped.
Add print statements within your thread.
Hope this helps.
since you didnt publish your code, i cant know exactly what you are doing, but you must declare WHAT you are stopping:
this.stopSelf();
as in:
public class BatchUploadGpsData extends Service {
#Override
public void onCreate() {
Log.d("testingStopSelf", "here i am, rockin like a hurricane. onCreate service");
this.stopSelf();
}
If by "doesn't work" you mean the process doesn't get killed, then that's how android works. The System.exit(0) or Process.killProcess(Process.myPid()) will kill your process. But that's not the Android way of doing things.
HTH
stopForeground(true);
stopSelf();
To let your service to stop itself.. create a BroadcastReceiver class.. In your service call your receiver like this..
In service
sendBroadcast(new Intent("MyReceiver"));
In Broadcast Receiver
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.stopService(new Intent(context,NotificationService.class));
}
}
Manifest file
<receiver
android:name="MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="MyReceiver"/>
</intent-filter>
</receiver>
Use stopSelf() to stop a service from itself.
I know this is an old question, but in my case (floating window as service) I had to remove the view first, and then call stopSelf().
windowManager.removeView(floatingView);
stopSelf();
I just ran into the same issue. In my case, I have a singleton service manager that I use to communicate with the service. In the manager the service is started like this:
context.bindService(new Intent(context, MyService.class), serviceConnection, Context.BIND_AUTO_CREATE);
By removing Context.BIND_AUTO_CREATE as suggested by Alik Elzin, I've been able to stop the service using this.stopSelf() and to have onDestroy() called when doing so. This problem is that after that I wasn't able to restart the service from the manager using the command above.
Finally I've fixed this by using a callback from the service that tells the manager to stop the service. This way the manager is always in charge when it comes to start/stop the service and everything seems to work fine. I don't know if there are any counter indications in doing it this way.
The code is really simple. Create a callback in the service and set it in the manager like this in your connection class:
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
myService = ((MyService.LocalBinder)service).getService();
myService.setCallback(new MyService.MyServiceCallback() {
#Override
public void onStop() {
stopService();
}
});
}
public void onServiceDisconnected(ComponentName className) {
myService = null;
}
};
and stop service:
public void stopService()
{
if(mServiceConnection != null){
try {
mContext.unbindService(mServiceConnection);
} catch (Exception e) {}
}
mContext.stopService(new Intent(mContext, BleDiscoveryService.class));
}
In the service, simply call myCallback.onStop() when you need to stop it.
Another dirty hack not mentioned here is to throw an exception like NPE. One day I needed to stop InputMethodService and this hack was useful.
if you use separate Thread in your service, after stopping service by calling stopSelf() or stopService() the Thread keeps running. if u want to stop Thread u should call Thread.interrupted() in the Thread(it might cause an Exception if Thread is already sleeping)