I start my service in onCreate() (if onCreate is called the first time) and call bindService in onStart(). The service probaply works, but after calling bindService my local instance of the service is still null. Furthermore, is seems to be that getService() is not called.?
Here is some code:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
if(savedInstanceState == null){
final Intent i = new Intent(this, HostService.class);
startService(i);
}
}
protected void onStart(){
super.onStart();
bindService(new Intent(this, StartGameActivity.class), connection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
HostBinder binder = (HostBinder) arg1;
hostService = binder.getService();
isBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
and in HostService:
...
private HostBinder binder = new HostBinder();
...
public class HostBinder extends Binder{
HostService getService(){
Log.d(TAG, "getService");
return HostService.this;
}
}
#Override
public IBinder onBind(Intent arg0) {
return binder;
}
Why is hostService still null, after onStart() is called and why is getService is not getting called ("getService" is not print in LogCat)?
thx & regards
You don't need to call startService(); it will be started by bindService().
In your onStart() method, you're creating an intent to launch StartGameActivity.class. Was that what you wanted, or did you mean to launch HostService.class?
If neither of those are your problem, we need more to go on. Can you put a logging statement inside your onServiceConnected() and onBind() methods so you can be sure they're called?
Any logcat messages that look interesting?
Are you talking to your service via the binder, or via messaging?
Related
My app use a background music service.
I have a button to quit my app but I can't find anything to close my app and my service.
I bind my service to my activity.
I tried:
unbindService(serviceConnection);
myService().stopSelf();
stopService(new Intent(this, MediaPlayer.class));
and absolutely nothing works !!! The service continues.
How can I do to destroy my service and how can I do to close my app ??
Tx
EDIT:
I use this in the onCreate method
Intent intent = new Intent(this, serviceClass);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
And in the MediaPlayer class
public class LocalBinder extends Binder {
public MediaPlayer getService() {
return MediaPlayer.this;
}
}
public IBinder onBind(Intent intent) {
Log.i(TAG, "service bound");
init();
return mBinder;
}
And that...
But I dont know if I really need to start the service. Bind the service already starts it
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Now I did this
#Override
public void onDestroy() {
player.stop();
super.onDestroy();
}
The onDestroy method works only if i unbind the service !
This doesnt work at all:
getService().stopSelf();
this.stopService(new Intent(this, MediaPlayer.class));
So, how can I stop the service and how can I close the app ?
This is what I do in my app. onDestroy() method from the activity will be called when you close your app.
private ServiceConnection musicServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
musicService.setCallbacks(MainActivity.this);
musicServiceBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "MusicService service disconnected (unbinded)");
musicServiceBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
Intent intent1 = new Intent(this, MusicService.class);
bindService(intent1, musicServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onDestroy() {
super.onDestroy()
if(musicServiceBound){
musicService.stopSelf();
unbindService(musicServiceConnection);
}
}
You wrote myService(), where you are creating another service using ().
For closing your app programmatically you can refer to this question.
I launch my app, the start is called, do the bind service and trigger the onServiceConnected. Everything is ok.
But...
When I press back, onStop is called, my bound var is true as excpected but the onServiceDisconnected is never called...
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart()
{
Log.e("START", "START");
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop()
{
Log.e("STOP", "STOP");
super.onStop();
// Unbind from the service
if (mBound)
{
this.unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName className, IBinder service)
{
Log.e("ON SERVICE START", "ON SERVICE START");
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocationService.LocationBinder binder = (LocationService.LocationBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0)
{
Log.e("ON SERVICE END", "ON SERVICE END");
mBound = false;
}
};
And my service
// Binder given to clients
private final IBinder mBinder = new LocationBinder();
/**
* 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 LocationBinder extends Binder
{
public LocationService getService()
{
// Return this instance of LocationService so clients can call public methods
return LocationService.this;
}
}
#Override
public IBinder onBind(final Intent intent)
{
Log.e("onBind", "onBind onBind onBind onBind onBind onBind");
return mBinder;
}
/** method for clients */
public int getRandomNumber()
{
return new Random().nextInt(100);
}
Every call to bindService() should be paired with a call to unbindService(). It actually doesn't matter if the binding worked or not. The point is to let Android know that you no longer want the connection to be active. Android will take care of the details of determining if the connection is currently bound and active and taking the appropriate action.
Bottom line is that you should not conditionally call unbindService() here. Simply always call it in onStop() with the same ServiceConnection that you used when calling bindService() in onStart().
I'm stuck in a problem with a service binding that is giving me nuts.
I got an activity that is binding a service, and is frequent that the user go in and out of that activity.
The problem comes when the user goes out first time of the activity this one unBinds the service and when is going in again, do not binds again.
The activity calls the binding service this way:
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, CService.class);
intent.putExtra("id_local", (String) getIntent().getExtras().get("id_local"));
intent.putExtra("id_send", (String) getIntent().getExtras().get("id_send"));
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
registerReceiver(uiUpdated, new IntentFilter("SERVER_MESAGE"));
mBound = true;
}
Where the mConnection is defined that way:
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
CService.LocalBinder binder =(CService.LocalBinder) service;
mService = binder.getService();
Log.d("Service", "onServiceConnected");
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.d("Service", "onServiceDisconnected");
mBound = false;
}
};
And in the onStop I unbindService:
#Override
protected void onStop() {
if (mBound) {
Log.d("ActivityStop", "Stoping activity");
unregisterReceiver(uiUpdated);
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
The onBind in the service is that one:
#Override
public IBinder onBind(Intent intent) {
final String id_local = intent.getStringExtra("id_local");
final String id_send = intent.getStringExtra("id_send");
if (!misatgesList.isEmpty()) {
misatgesList.clear();
}
mBackGroundTimer.schedule(new TimerTask() {
#Override
public void run() {
String serverResult = restRecive(id_local, id_send,
misatgesList.size());
if (serverResult != null) {
misatgesList.addAll(procesMisatges(serverResult,
id_local));
Intent i = new Intent("SERVER_MESAGE");
i.putExtra("recive", serverResult);
sendBroadcast(i);
}
}
}, 0, 1000);
return mBinder;
}
And the onUnBind is that one:
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//stopSelf();
return super.onUnbind(intent);
}
So my question would be, how I can bind again the service when the activity goes in again? Or what should I do to keep the binding alive until the user goes in the activity?
I found the solution!
What I meant was how to call again the onBind. That is done using the onRebind, that alows you to call again the onBind.
So, I created the onRebind:
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
}
Also, for the onRebind to work, you have to turn the return in the onUnbind to true.
#Override
public boolean onUnbind(Intent intent) {
mBackGroundTimer.cancel();
misatgesList.clear();
Log.d("ServiceOnUnBind", "ServiceOnUnBind");
//return super.onUnbind(intent);
return true;
}
For more explanation, check there: Bound Services
Use getApplicationContext() API when binding to your service from Activity as below:
getApplicationContext().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
getApplicationContext returns the global application context - the difference from other contexts is that for example, an activity context may be destroyed (or otherwise made unavailable) by Android when your activity ends. The Application context remains available all the while your Application object exists (which is not tied to a specific Activity)
I got a problem with binding a service:
I use following code:
protected void onCreate(){
...
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
if(mService != null)
Log.e(TAG, "is instantiated (onClick)!");
});
}
protected void onStart(){
super.onStart();
bindService(new Intent(this, HostService.class), connection, Context.BIND_AUTO_CREATE);
if(mService == null)
Log.e(TAG, "is null (onStart)!");
}
...
After starting my activity "is null (onStart)!" is printed in LogCat.
When I click the button "is instantiated (onClick)!" is printed.
Why bindService() doesnt instantiate my service-instance mService directly and how can I solve the problems referring to this?
thx & regards
Why bindService() doesn't instantiate my service-instance mService directly
bindService() is asynchronous, like many operations in Android, so it occurred after your test in onStart.
how can I solve the problems referring to this?
Put your business logic in onServiceConnected() of your ServiceConnection, instead of immediately after the bindService() call.
Here is an example of the ServiceConnection code:
private ServiceConnection sConn;
private Messenger messenger;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
// Service Connection to handle system callbacks
sConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
messenger = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We are conntected to the service
messenger = new Messenger(service);
}
};
// We bind to the service
bindService(new Intent(this, ConvertService.class), sConn,
Context.BIND_AUTO_CREATE);
}
This is from Francesco Azzola's good example.
I have a service which is binded to application context like this:
getApplicationContext().bindService(
new Intent(this, ServiceUI.class),
serviceConnection,
Context.BIND_AUTO_CREATE
);
protected void onDestroy() {
super.onDestroy();
getApplicationContext().unbindService(serviceConnection);
}
For some reason, only sometimes the application context does not bind properly (I can't fix that part), however in onDestroy() I do unbindservice which throws an error
java.lang.IllegalArgumentException: Service not registered: tools.cdevice.Devices$mainServiceConnection.
My question is: Is there a way to call unbindservice safely or check if it is already bound to a service before unbinding it?
Thanks in advance.
Try this:
boolean isBound = false;
...
isBound = getApplicationContext().bindService( new Intent(getApplicationContext(), ServiceUI.class), serviceConnection, Context.BIND_AUTO_CREATE );
...
if (isBound)
getApplicationContext().unbindService(serviceConnection);
Note:
You should use same context for binding a service and unbinding a service. If you are binding Service with getApplicationContext() so you should also use getApplicationContext.unbindService(..)
Here you can find a nice explanation and source codes how to work with bound services. In your case you should override methods (onServiceConnected and onServiceDisconnected) of ServiceConnection object. Then you can just check mBound variable in your code.
Doing exactly what Andrey Novikov proposed didn't work for me.
I simply replaced:
getApplicationContext().unbindService(serviceConnection);
With:
unbindService(serviceConnection);
I found there are two issues. Attempting to bind more than once and also attempting to unbind more than once.
Solution:
public class ServiceConnectionManager implements ServiceConnection {
private final Context context;
private final Class<? extends Service> service;
private boolean attemptingToBind = false;
private boolean bound = false;
public ServiceConnectionManager(Context context, Class<? extends Service> service) {
this.context = context;
this.service = service;
}
public void bindToService() {
if (!attemptingToBind) {
attemptingToBind = true;
context.bindService(new Intent(context, service), this, Context.BIND_AUTO_CREATE);
}
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
attemptingToBind = false;
bound = true;
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
bound = false;
}
public void unbindFromService() {
attemptingToBind = false;
if (bound) {
context.unbindService(this);
bound = false;
}
}
}
Why do we get this error?
When you try to unregister a service which is not registered.
What are some common examples?
Binding and Unbinding a service with different Context.
calling unBind(mserviceConnection) more than bind(...)
First point is self explanatory. Lets explore the second source of error more deeply. Debug your bind() and unbind() calls. If you see calls in these order then your application will end up getting the IllegalArgumentException.
How can we avoid this?
There are two ways you should consider to bind and unbind a service in Activity. Android docs recommend that
If you want to interact with a service only when the Activity is visible then
bindService() in onStart() and unbindService() in onStop()
Your Activity {
#Override
public void onStart(){
super.onStart();
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
#Override
public void onStop(){
super.onStop();
unbindService(mConnection);
}
}
If you want to interact with a service even an Activity is in Background then
bindService() in onCreate() and unbindService() in onDestroy()
Your Activity {
#Override
public void onCreate(Bindle sis){
super.onCreate(sis);
....
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
#Override
public void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
I think that guide is not completely correct as mentioned here Surya Wijaya Madjid. Memory leaks can occur when bound service is destryed and not re-connected yet.
I think that this approach is needed:
Service mService;
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
boolean bound = false;
#Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((MyService.ServiceBinder) service).getService();
if (!bound)
{
// do some action - service is bound for the first time
bound = true;
}
}
};
#Override
public void onDestroy()
{
if (mService != null)
{
// do some finalization with mService
}
if (mServiceConnection.bound)
{
mServiceConnection.bound = false;
unbindService(mServiceConnection);
}
super.onDestroy();
}
public void someMethod()
{
if (mService != null)
{
// to test whether Service is available, I have to test mService, not mServiceConnection.bound
}
}
Use a variable to record if you have ever bind to a service, and unbind it if the variable is true.
See android official example :
http://androidxref.com/9.0.0_r3/xref/development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java#376
Not sure about all the above answers, it seemed far too complicated while none of these would fit the issue I had.
Only binding/unbinding once at a time, and the service was definitely bound at the time of the unbind() call. Don't want to leak anything, so I just made sure I was using the same context for the bind() and unbind() calls and that solved it permanently! Doing something like this:
any_context.getApplicationContext().bind(...);
...
another_context.getApplicationContext().unbind(...);