How to inject a bound service into an Activity via dagger? - android

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.

Related

IBinder between Bound Service and Activity

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.

Getting object of service

I'm trying to get my Services object and I'm doing that with this code
public class Service extends android.app.Service {
private Handler handler = new Handler();
static Service SELF;
MainActivity mainActivity;
BluetoothSPP bluetoothSPP;
public static Service getInstance() {
return SELF;
}
#Override
public void onCreate() {
super.onCreate();
SELF = this;
}
}
but after starting service getInstance() gives null. why?
Service and Activity is a different components, managed by Android, so you should not save reference to Activity insie Service.
Solution in this case - use Service binding - you can move all your methods into separate interface, by which your Service and Activity will communicate and return it from Binder once Service is bound to Activity. See: https://developer.android.com/guide/components/bound-services.html, Bind service to activity in Android

Use Service or Binder object to set variable inside Service

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;
}
}

Bind to a service - call back when bind has been successfully - Android

I've come to a point where I don't know an elegant way to do this.
Let's say I've a Fragment, named FragmentA, and a Service named BackupService
On FragmentA I bound it to the BackupService using:
private ServiceConnection backupServiceConnection = 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;
backupBoundService = binder.getService();
isBound = true;
// How to let the fragment know this has happened?
// Use an eventBus? EventBus.getDefault().post(backupBoundService); ?
Log.d(TAG, "On Service Connected -> Yup!");
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
And:
Intent intent = new Intent(ApplicationContextProvider.getContext(), BackupsService.class);
ApplicationContextProvider.getContext().bindService(intent, backupServiceConnection, Context.BIND_AUTO_CREATE); // Using application context
Now I know the binding is an asynchronous task and here is where my question comes in.
I came up with the idea of using an EventBus but I don't find it elegant as the fragment would be posting the object (in this case backupBoundService), referencing the service, and at the same time would be listening/receiving the event from the bus, eg, would be the same fragment posting and receiving the event (posting to himself).
Is there an elegant way to get a reference for the running service when the fragment is bounded to it? I'm quite sure there's a pattern for this case but I've been googling and searching here to no luck so far.
Hi you can use eventbus or you can create simple call back methods using Interfcae for you requirement.
If you don't have idea to create call backs using interface then look this piece of code.
It is same like eventbus :)
// The callback interface
interface MyCallback {
void callbackCall();
}
// The class that takes the callback
class Worker {
MyCallback callback;
void onEvent() {
callback.callbackCall();
}
public void setCallBack(MyCallback callback)
this.callback=callback;
}
/////////////////////////////
class Callback implements MyCallback {
....
Worker worker= new Worker()
Worker.setCallback(this);
.. .
void callbackCall() {
// callback code goes here
//onEvent this method will execute
}
}
Hope this will helpful.
Good luck :)

Accessing resources within a service (Android)

I'm a fairly new developer to android, so I get the feeling there's some property of services that I am overlooking. Please let me know.
Everything seems to be working just fine as far as services go. I have an IntentService class that looks like this:
public class MyIntentService extends IntentService
{
myClass myObject;
int test;
public MyIntentService()
{
super("MyIntentService");
test = 12;
myObject = new myClass(this, R.raw.file);
}
#Override
public IBinder onBind(Intent intent)
{
return new LocalBinder<MyIntentService>(this);
}
#Override
protected void onHandleIntent(Intent intent) {
}
The constructor for myClass accepts a Context, and then an int for the raw resource. If I call the constructor in an Activity class it works just fine. The service itself also seems to be working because if I comment out the object stuff, I can retrieve the test int no problem.
So what am I missing here?
Thank you very much!

Categories

Resources