I am using a BraodCastReceiver that starts an IntentService. Everythings look working good, but I get this error which I don't know its source:
android.app.ServiceConnectionLeaked: Service com.merchantech.app.smartdiscount.MyIntentService has leaked ServiceConnection com.clover.sdk.v3.order.OrderConnector#535008f4 that was originally bound here
at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:969)
at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:863)
at android.app.ContextImpl.bindService(ContextImpl.java:1426)
at android.app.ContextImpl.bindService(ContextImpl.java:1415)
at android.content.ContextWrapper.bindService(ContextWrapper.java:473)
at com.clover.sdk.v1.ServiceConnector.connect(ServiceConnector.java:119)
at com.clover.sdk.v1.ServiceConnector.waitForConnection(ServiceConnector.java:148)
at com.clover.sdk.v1.ServiceConnector.execute(ServiceConnector.java:209)
at com.clover.sdk.v3.order.OrderConnector.getOrder(OrderConnector.java:153)
at com.merchantech.app.smartdiscount.MyIntentService.onHandleIntent(MyIntentService.java:41)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.os.HandlerThread.run(HandlerThread.java:60)
Here's my BrodcastReceiver class:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("com.test.intent.action.LINE_ITEM_ADDED")) {
Intent i = new Intent(context, MyIntentService.class);
context.startService(i);
}
}
}
And here's my IntentService class:
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
orderItem.addLineItem(orderId, lineItemId, var);
}
}
The error message basically means that some component created a binding to a Service and did not unbind from the service before the component was destroyed.
You will need to provide more information about your app's structure to get a better answer to your question. I'll make some guesses, and maybe give you some ideas about things to explore.
I'm guessing that you are using a library from Clover and maybe also Merchantech. Or maybe the Clover library uses a Merchantech library. I'm also guessing that orderItem is an instance of a class defined by Clover, not you.
The Android runtime destroys an IntentService after onHandleIntent() completes and there are no more Intent requests queued. You can confirm this by adding the onDestroy() method to your MyIntentService with a Log command to show when it is called. That means that in the code you posted for onHandleIntent(), your IntentService will be destroyed soon after the call to addLineItem() completes.
The stack trace suggests that the processing triggered by the call to orderItem.addLineItem() causes a binding to another service. Somewhere, that binding is not being managed properly--maybe not unbound when it should be. Is there something the Clover subsystem expects you do to "close" it or "release" resources when your component (Service or Activity) is being destroyed?
Solved:
The problem is due to the Clover SDK. They have not unbind a service that was bounded somewhere in the com.clover.sdk.v3.order.OrderConnector Class. So the problem is not relevant to the code snippet above.
Related
I had to implement a feature to this app which consists of an Activity and a Service working on the background (it implements Service, not IntentService).
I went through a few tutorials on the Internet that are supposed to work, and they all use LocalBroadcastManager, which by the way is the recommended by Android:
If you don't need to send broadcasts across applications, consider
using this class with LocalBroadcastManager instead of the more
general facilities described below.
I literally lost a day to find out the problem why it wouldn't work for me: it only works if I use Context.sendBroadcast(). and Context.registerReceiver() instead of the LocalBroadcastManager methods.
Now my app is working, but I feel I am going against the best practices, and I don't know why.
Any ideas why it could be happening?
EDIT:
After I wrote this question I went further on the problem. LocalBroadcastManager works through a Singleton, as we should call LocalBroadcastManager.getInstance(this).method(). I logged both instances (in the Activity and in the Service) and they have different memory addresses.
Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be
the same.
Any thoughts on that? (sorry for the long post)
Code samples:
MyService
public class MyService extends Service {
...
// When an event is triggered, sends a broadcast
Intent myIntent = new Intent(MainActivity.MY_INTENT);
myIntent.putExtra("myMsg","msg");
sendBroadcast(myIntent);
// Previously I was trying:
// LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(myIntent);
}
MyActivity
public class MainActivity {
...
private BroadcastReceiver messageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("onReceive", "received!");
// TODO something
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
// Previously I was trying:
// LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(messageReceiver, new IntentFilter(MY_INTENT));
}
}
I've never used LocalBroadcastManager, but it sounds like you have to register your receiver on there (i.e. lbm.registerReceiver(...), not mycontext.registerReceiver(...)). Are you doing that?
Now I came to another question, shouldn't a Service have the same Context as the Activity that called it? From this article a Service runs on the Main Thread, hence I'd think the Context would be the same.
The Context class is not related to threads. In fact, both Service and Activity are (indirect) subclasses of Context -- so they're their own Contexts! That's why you can use "this" as a Context.
But regardless of which context you send into LocalBroadcastManager.getInstance(), you should be getting the exact same LBM instance out. I can't think of any reason that you wouldn't -- except if you're running the Activity and Service in different processes?
Declaration:
private BroadcastReceiver receiver;
Initialization:
receiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
//todo
}
};
Registration:
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, new IntentFilter("RECEIVER_FILTER"));
context can be any type of Context, you can use the application context.
Unregister:
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
Broadcast:
Intent intent = new Intent("RECEIVER_FILTER");
intent.putExtra("EXTRA", someExtra);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
check out if your Service and Activity are run in different process, LocalBroadcastManager can't apply in different process.(you should see it in AndroidManifest.xml file)
I have a trouble with screen orientation when using AsyncTask even it's inside Service.
My service look like:
public class RequestService extends Service {
private MyBinder binder;
public RequestService(){
binder = new MyBinder(RequestService.this);
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MyBinder extends Binder{
private final RequestService service;
public MyBinder(RequestService service){
this.service = service;
}
public RequestService getService(){
return this.service;
}
}
public <T> void sendRequest(Request<T> task, INotifyRequest<T> notify){
// Call excute the asynctask and notify result in onPostExcute
new TaskExecutor<T>(task, notify).execute();
}
}
Update: I use my Service like this:
// start the service
final Intent intent = new Intent(context, serviceClass);
context.startService(intent);
// then bound the service:
final Intent intentService = new Intent(context, serviceClass);
// Implement the Service Connection
serviceConnection = new RequestServiceConnection();
context.getApplicationContext().bindService(intentService, serviceConnection,
Context.BIND_AUTO_CREATE);
When orientation changing, the service is unbound then re-bound, the AsyncTask doesn't notify to update UI. I wonder why it could happen even AsyncTask inside the Service?
I have read this post, but I don't want to lock the screen orientation or something like that. I prefer the Service than IntentService as Service 's flexible, I can use it with the Binder to get Service instance.
So, the question is, is there any way to do thread safe inside the Service rather than AsyncTask?
If you use a bound service keep in mind, that the Service will be destroyed if no Activity is bound. I don't know if you unbind in onPause(), but this would destroy your Service at an orientation change.
Because of this you will loose the Service and the reference to the AsyncTask. Furthermore there is no onRetainInstanceState() available for a Service, to save the AsyncTask and grab it again.
Think about an IntentService in this case it would be the proper way. Or if you wanna keep the Service use startService(), to keep it alive while no Activity is bound. Then you can still bind and unbind from the service the way you want.
The next point is to keep a reference of the AsyncTask. Because you have to set your callback again if the Activity was destroyed. Because the callback reference will still be set to the old Activity.
Hope this helps.
Edit:
Well if you read that maybe you consider using a IntentService or something..
Keep a instance of the AsyncTask in the Service and define a setter in your Task for your callback.
If your Activity binds to the service after the orientation change check, whether the AsyncTask is running. If it's running update the callback. You can use your Binder for that.
I have been looking for some way to get the ServiceConnection when I start my Service using startService(...).
I haven't found a way, so I have been searching a bit and found this:
Does each Activity need to Bind to a Service & What happens when it was created with startService()
There, Commonsware says that it doesn't matter if I call bindService after the startService call.
So I thought that I first run startService(...) and then directly after do a bindService(...) (so that onServiceConnected is called). But then the Service.onCreate is executed twice. Probably because startService isn't "finished" yet...?
Question is: How do I get a reference to my Service (the IBinder), ie. how do I get the onServiceConnected to fire if I start my Service with startService?
--- EDIT ---
I still do want to know any answers and ideas you might have. I made a "hack" to get around this:
I simply made a static reference (in SRef.java I have public static IBinder myBinder = null), and in my Service.onCreate I simple do
SRef.myBinder = myBinder;
This doesn't seem right to me, so any other ideas on how it is supposed to work would be appreciated.
I use the exact same technique (a samba client service), onCreate is never called twice for me and I get the binder (by connection callback) as I would expect. A new start of activity doesn't fire a onCreate either because previous startService performed the startup of the service already.
Here is my code (might be trivial, but maybe it helps):
Activity (onCreate):
startService(new Intent(this, SambaService.class));
bindService(new Intent(this, SambaService.class), sambaServiceConnection,
Context.BIND_AUTO_CREATE);
Service:
private ServiceBinder mServiceBinder = new ServiceBinder();
public class ServiceBinder extends Binder {
public SambaService getService() {
return SambaService.this;
}
}
public IBinder onBind(Intent intent) {
return mServiceBinder;
}
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)