I have a service with an inner binder class:
public class MyService extends Service{
private final ServiceB binder = new ServiceB();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
//inner binder class
class NewsServiceB extends Binder{
....
}
my question is: is this pattern ok?Or I should make the binder class static, maybe with a WeakReference to service?Mind that EVERY binder method make use of service's methods, so making it non static is very useful as code is cleaner and more immediate.
I fear memory leaks, neverthless no warnings show...
Related
Maybe I'm just tired. However I am struggling to understand just how the IBinder interface works.
A service has a method call onBind(Intent intent) and this passes some form of the IBinder to a binding activity.
Where I am struggling is how to visualize this. Is an IBinder object a pipe between the service and activity, so that an activity can interact directly with the service? Or is an IBinder an object that is passed to the activity that has information from the Service in it (similar to an intent)?
Edit: The idea is for me to be able to call the getSomeData function from the binding activity. Or rather, the idea is to get the mSomeData obect to the activity.
I have the following classes that I am using, and Im trying to figure out the best way to have the activity request data (serializable if needed though I'd rather not) from the service.
public class MainService extends Service{
private CustomBinder mIBinder;
private SomeDataObject mSomeData;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mIBinder = new CustomBinder();
return super.onStartCommand(intent, flags, startId);
}
#Override
public CustomBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// This is auto generated and I havent changed it yet. I am not
// Experiencing errors as this is not designed to run yet.
throw new UnsupportedOperationException("Not yet implemented");
}
public final SomeDataObject getSomeData(){
return mSomeData;
}
class SomeBinder extends MainEngineBinder{
// All the Auto Generated Stuff
}
}
You don't need to know how IBinder works. Just subclass Binder (Not IBinder) and add some methods to the Binder subclass. These methods can be called from the activity bound to your service.
The easiest way to do this in your case is to have an inner class extend Binder, and that inner class will then be able to access methods/fields from your service and return them to the activity. You look like you're working from a similar template as the Android documentation on bound services, so here's the example from the docs - all the binder does in this case is expose a getter for getting the service itself, and a caller can simply call methods directly on the service:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* 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;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
The caller calling bind() will need to cast the IBinder to LocalService.LocalBinder. In this case, the IBinder is neither a pipe nor an intent-like object; it is a normal Java-style interface.
Note that all of this holds true if you are not doing IPC. The documentation states that in this case (same application, same process) the call is a normal Java call - you can pass objects, references, whatever you like, because everything is in the same process.
Note that IPC, pipes, marshalling, serialisation and the like are all unnecessary (unless you want your service to be called from other apps or if you use multi-process apps). An Android service is not even run in a separate thread unless you start a new thread explicitly, and does not have it's "own" thread or process - all calls made to binders or the service object itself are made in the same thread as the caller.
In your case, the exact example from the Android documentation seems like the best approach.
I have a service class that extends InputMethodService. When i want to bind this service to my ActivityMain, at code below i get the "Cannot override the final method from AbstractInputMethodService" error.
public class MyIME extends InputMethodService
implements KeyboardView.OnKeyboardActionListener, OnSharedPreferenceChangeListener {
//some code here...
#Override
public IBinder onBind( Intent intent ) {
return binder;
}
What is this error and how to fix it?
What is this error
onBind() is declared as final in AbstractInputMethodService. You cannot override it.
and how to fix it?
Delete your onBind() method.
I can either set an variable int[] by using the binder object or using the service class object itself. Code is in public class MyActivity extends Activity. Which one is the way to go, both works:
private BackgroundService.BackgroundBinder mBoundBinder; // to get methods of nested binder class inside BackgroundService
private BackgroundService mBoundService; //service class object
public void onServiceConnected(ComponentName className, IBinder binder) {
mBoundService = ((BackgroundService.BackgroundBinder) binder).getService(); //google version
mBoundBinder = ((BackgroundService.BackgroundBinder) binder);
}
Service int[] array can be set in two ways:
1. mBoundService.setListeners = genArr(); //genArr() returns int[]
2. mBoundBinder.setListeners(genArr());
Google android.developer version uses following inside Service class. This shrinks the necessary nested Binder class down to one method returning the service object itself, thus its methods can directly be accessed. Nice.
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
I would like to inject a bound service into my activity via Dagger2.
My Service is declared as follow:
Public class MyService extends Service{
private final IBinder mBinder = new LocalBinder();
...
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void doBackgroundTask() {
...
}
}
My Activity:
public abstract class MainActivity extends AppCompatActivity {
#Inject
MyService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
service.doBackgroundTask();
...
}
How would you achieve that ? Where will you put the ServiceConnection (into a base class, inside the module) ?
Thanks a lot.
I don't think that injecting the service that way (via injected field) will work because you don't control the instantiation of the service's object.
If your service contains fields that need to be injected you will have to inject in onCreate() the same way you inject your activities, i.e. calling DaggerMyAppComponent.inject(this).
About the ServiceConnection: you will have to do it the usual way as described in http://developer.android.com/guide/components/bound-services.html
I was dealing with the same concept/problem and like #Ognyan says - you won't have control over creating service.
I think this: How to access service functions from fragment, which is bound to parent activity in Android? might help you.
You may instantiate service in Application/Activity and communicate with it as described in the attached link.
You may also think of putting the interface (which is communicating with service) in base abstract class (BaseActivity or BaseFragment) which Fragment/Activity inherits and then easily reach the interface in any fragment or activity you need.
Hope it solves your issue.
I making Service with Handler and I need Handler to use some Service methods. As Handler must be static, I can access Service methods without Service reference in Handler.
So I did this way:
private static class ServiceHandler extends Handler {
MyService service;
public ServiceHandler(MyService service) {
this.service = service;
}
#Override
public void handleMessage(Message msg) {
...
}
}
But also found that this is the right way to do the job:
private static class ServiceHandler extends Handler {
private final WeakReference<MyService> mMyService;
public ServiceHandler(MyService service) {
mMyService = new WeakReference<MyService>(service);
}
#Override
public void handleMessage(Message msg) {
MyService service = mMyService.get();
...
}
}
What is the difference in this two ways to use Service in Handler?
The first code example sets a member variable to a reference of the calling Service (which I assume is the outer class of this inner class). This is exactly the same as if you had removed the static keyword for the inner class, because now the inner class is holding a reference to an instance of the Service class (which is what you are usually trying to avoid when you use the static keyword).
The second code example uses a weak reference, which means that the garbage collector can clean up (destroy) the instance of the Service class, even though you are holding a reference to it in your Handler. If that occurs, the call to mMyService.get() will return null, so you had better check for that in your code.
In practice, there are no differences between these 2 code examples since you won't be using the Handler once the Service has been destroyed.