I have a messaging app based on webscokets that relies on a background service to send and receive messages. Once the service is started, I need it to run indefinitely in the background, even when the app closes as well as the phone goes into sleep mode.
In the app, the service is started just as a user logs in, and in the onCreate method as startService(new Intent(LoggingIn.this, MessagingService.class));
How can I setup my service to run permanently in the background?
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
imService = ((MessagingService.IMBinder) service).getService();
if (imService.isUserAuthenticated() == true) {
// Intent i = new Intent(LoggingIn.this, ListOfFriends.class);
Intent i = new Intent(LoggingIn.this, MainActivity.class);
startActivity(i);
LoggingIn.this.finish();
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
imService = null;
Toast.makeText(LoggingIn.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Start and bind the imService
*/
startService(new Intent(LoggingIn.this, MessagingService.class));
...etc
Use startForeground() in your onStartCommand() method in your service.
you need to use START_STICKY in the onStartCommand:
http://developer.android.com/reference/android/app/Service.html#START_STICKY
Then you can read this thread to start your service during boot:
Android -Starting Service at Boot Time
You need to define a name for the service in the manifest to make it run in a different thread: android:process=":my_process" so it will continue to run inbackground if you close the app
Related
I have a background Service that need to be running even if the application gets killed by Android. This is currently working perfectly.
My problem is that when I restart the application (with the background service still running), I want my Activity to bind to the service to have access to some of its methods. When I try to bind with a ServiceConnection, the onServiceConnected is never called.
final private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "onServiceConnected"); //this is never called
MyBackgroundService.ServiceBinder binder = (MyBackgroundService.ServiceBinder) service;
backgroundService = binder.getService();
}
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "onServiceDisconnected");
backgroundService = null;
}
};
private void bindBackgroundService(){
this.bindService(new Intent(this, MyBackgroundService.class), serviceConnection, Context.BIND_AUTO_CREATE);
}
Am I doing this the wrong way? Is it better to stop the Service and restart it?
Since the class that binded the background service is a singleton and my alarm broadcast receiver that is making sure the background service is always running instantiates this singleton, I had access to this singleton and I was trying to bind to the service that was already binded.
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.
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.
Which is really for a music player? What's the difference on their behavior? Please let me understand! I'm really confused on what to use. I tried making a music player with a bind service but the problem is every time I exit my application and enter it again, it seems like a new serviceConnection is started. I'm expecting that every time I go back to my app, it would still recognize that the music is already fired up. For an instance I have play and pause functions. When i play the music, exit the app, and return, I would be expecting that I could stop the player. But instead, it will play another music. So now I'm confused, should i really use bind? or started service?
public class MyService extends Service{
public IBinder myBinder = new MyPlaylistBinder();
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return myBinder;
}
public class MyPlaylistBinder extends Binder{
MyService getService(){
return MyService.this;
}
}
The code above is my MyService.java
public ServiceConnection myConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
MyPlaylistBinder binder = (MyPlaylistBinder) service;
myService = binder.getService();
Toast.makeText(getApplicationContext(), "Service is connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Service is disconnected", Toast.LENGTH_SHORT).show();
}
};
And this one is a portion of my MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnPrevious = (ImageButton)findViewById(R.id.btnPrevious);
btnBackward = (ImageButton)findViewById(R.id.btnBackward);
btnPlay = (ImageButton)findViewById(R.id.btnPlay);
btnForward = (ImageButton)findViewById(R.id.btnForward);
btnNext = (ImageButton)findViewById(R.id.btnNext);
ComponentName myService = startService(new Intent(this, MyService.class));
Intent intent = new Intent(this, MyService.class);
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
listview = (ListView)findViewById(R.id.listView1);
ContentResolver resolver = getContentResolver();
Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
cursor = resolver.query(uri, null, null, null, null);
Above is a portion of the MainActivity's onCreate()
As you can see I'm not using an AIDL because I haven't tried that and I'm afraid I might make it worse. Please bear with me, I'm just a beginner in android :(
Documentation:
Started
A service is "started" when an application component (such as
an activity) starts it by calling startService(). Once started, a
service can run in the background indefinitely, even if the component
that started it is destroyed. Usually, a started service performs a
single operation and does not return a result to the caller. For
example, it might download or upload a file over the network. When the
operation is done, the service should stop itself.
Bound
A service is
"bound" when an application component binds to it by calling
bindService(). A bound service offers a client-server interface that
allows components to interact with the service, send requests, get
results, and even do so across processes with interprocess
communication (IPC). A bound service runs only as long as another
application component is bound to it. Multiple components can bind to
the service at once, but when all of them unbind, the service is
destroyed.
Based on that, you probably want to start a service since you intend it to keep running after the components that started it are no longer there. As a convenience to the user, you should consider having an ongoing notification as long as the service is running, and include music controls that lets the user directly pause, resume, or completely stop playback (that last one could invoke stopService, at which point you cancel the notification).
I'm trying to bind a service, but onBind() always returns false.
This is the code for the ServiceConnection-
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with our service has been established,
// giving us the service object we can use to interact with our service.
mBoundService = ((ScheduleService.ServiceBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
This is call to bindService() -
boolean test = getApplicationContext().bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
This is the declaration of the service in the Manifest -
<service android:name=".Notifications.ScheduleService" android:enabled="true"/>
I've read previous questions regarding the subject and couldn't find an answer(tried switching the Activity context with the Application context, but it didn't help).
I'm using using Frgaments and ActionBarSherlock, and my Activity extends SlidingFragmentActivity (That's why i'm using the application context, which doesn't help).
Edit - This is the code of the service i'm trying to start -
public class ScheduleService extends Service {
/**
* Class for clients to access
*/
public class ServiceBinder extends Binder {
public ScheduleService getService() {
return ScheduleService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("ScheduleService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly stopped, so return sticky.
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
// This is the object that receives interactions from clients. See
private final IBinder mBinder = new ServiceBinder();
/**
* Show an alarm for a certain date when the alarm is called it will pop up a notification
*/
public void setAlarm(Calendar c) {
// This starts a new thread to set the alarm
// You want to push off your tasks onto a new thread to free up the UI to carry on responding
new AlarmTask(this, c).run();
}
}
Any help will be appreciated . Thanks.
What is the fully qualified class-name of ScheduleService (i.e. including the full package-name)?
I'm asking this, because in your AndroidManifest.xml file, your service's name is .Notifications.ScheduleService, which seems a bit odd:
This tells me that either
The (last part of the) package-name contains a upper-case
character... not so good.
I would expect .notifications.ScheduleService instead, if this is the case.
The ScheduleService is defined within a file called Notifications.java.
I would expect .Notifications$ScheduleService instead, if this is the case (dollar sign instead of period).
Do you mean bindService() returns false? onBind() returns IBinder type.
Keep in mind that service binding takes some time. If you want to perform some action after binding is done you can perform it in the onServiceConnected() method.
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((ScheduleService.ServiceBinder) service).getService();
Calendar c = new Calendar();
mBoundService.setAlarm(c);
}
If you need more guidance on this you need to show us your Activity code.
Why do you use the application context to bind the service?
The method bindService is called through the ContextWrapper. It might not be the issue but I'd share contexts across the place where you bind the service and where you have the connection.
In your case instead of
boolean test = getApplicationContext().bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
I'd do the following
boolean test = bindService(new Intent(this, ScheduleService.class), mConnection, Context.BIND_AUTO_CREATE);
Or if you want to keep a global context within the application, move everything to your Application file and call it similarly the same way suggested above.
The issue can also be on the package name of your app and the declaration of your service in your manifest. If you are unsure make sure to give the global route to your service in the manifest.