Currently, I need a bound (Music)Service, because I need to interact with it. But I also want it to not be stopped, even when all components have unbound themselves.
As the Android Developer Guide says
"[...] Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed."
The Guide also says
"[...] your service can work both ways—it can be started (to run indefinitely) and also allow binding."
In my application, the service is started when the application starts.
I want to have this service destroyed only by a user-click on a close-button I am displaying in a custom notification. But currently, when I am destroying my MainActivity the service also stops.
This is where I am now, this is called when I want to create my Service:
public void createServiceConnection(){
musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
musicSrv = binder.getService();
attachMusicService();
}
};
}
...which calls this:
public void attachMusicService(){
playerFragment.setMusicService(musicSrv);
musicSrv.attach(context); //need this for my listeners, nevermind
bindService(context);
}
...which calls this:
public void bindService(Context act){
if(playIntent==null){
playIntent = new Intent(act, MusicService.class);
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}else{
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}
//finished. I can do stuff with my Service here.
}
Have I misunderstood something?
I feel like the service should keep running, even the activity is destroyed, because I first made a started service and then bound to it.
Bind to your service from custom Application class. I don't think you can keep service alive after activity that's bound to it is destroyed (when onDestroy is called). You can keep service alive if activity pauses (onPause) by calling startForeground from service
Seems like the code was correct.
According to this Question I found out that my problem was the notification I displayed, wich is pretty interesting.
Seems like that a Service that is created for running indefinitely needs to have a Notification wich is displayed by startForeground(NOTIFY_ID, notification);.
I showed my notification with notificationmanager.notify(NOTIFY_ID, notification); before, now I have
`notificationmanager.notify(NOTIFY_ID, notification);
startForeground(NOTIFY_ID, notification);`
and the service won't stop anymore after all my bound Activities are destroyed.
Related
What I have going on is that I made a simple service in Xamarin.Android which for now simply just sends a single Local Push Notification.
In my main application (MainActivity) I have made a statement that checks whether or not this service runs. If it does not, I will simply start the service, otherwise I'll do nothing.
if (UtilityController.IsServiceRunning(typeof(WidgetService), this) == false)
{
StartService(new Intent(this, typeof(WidgetService)));
}
This works fine aswell. No problems here.
Now, the issue is when it comes to my Service being ran multiple times.
[Service]
public class WidgetService : Service
{
public override StartCommandResult OnStartCommand(Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
SendPushNotification();
return StartCommandResult.Sticky;
}
//Other functions such as OnBind, OnDestroy etc..
}
Here I have a service that is straight forward. It's only purpose is to send a Push Notification in the function SendPushNotification(); which it does.
However, when I'm using different StartCommandResult enums, my OnStartCommand function gets triggered in different ways (which I assume is because it restarts the service):
Using StartCommandResult.Sticky makes the Service restart itself every time I close/kill the main app.
Using StartCommandResult.NotSticky makes the Service restart itself every time I start the main app.
This is a problem. I want the Service to only be run ONCE while it's still running. I don't want it ever to be restarted unless I specifically tells it to.
How do I achieve this?
Based on the info you have provided, what is happening should be something like this:
While using StartCommandResult.Sticky: As you have described, service is being restarted when you kill the service process. But this time OnStartCommand is being called with a null intent.
While using StartCommandResult.NotSticky: In this case, service is being stopped when you kill the process but notifications are not removed. When you start the app again, since service is not started, it will start a fresh from your activity.
What you could do depends on the behaviour you do expect from your app. If you want the service to stop when you close/kill the app, you can do something like this:
[Service]
public class WidgetService : Service
{
bool isStarted;
public override StartCommandResult OnStartCommand(Android.Content.Intent
intent, StartCommandFlags flags, int startId)
{
if (!isStarted)
{
SendPushNotification();
isStarted = true;
}
return StartCommandResult.NotSticky;
}
//Only will be called if stopWithTask attribute is set to false
public override void OnTaskRemoved(Intent rootIntent)
{
// Remove the notification from the status bar.
base.OnTaskRemoved(rootIntent);
}
public override void OnDestroy()
{
// We need to shut things down.
// Remove the notification from the status bar.
isStarted = false;
base.OnDestroy();
}
}
And stop the service when you are done with it or app is being closed. But if you want to keep the service running, since you are displaying a notification, I would suggest to make your service a foreground service
I am writing a Tracking App in Android.
I have got a Service implements LocationListener, which does all the stuff with location and writing to database, and Activity.
I would like to run Service in new thread to optimize my app. I want also to send both sides messsages from Service to Activity, which will show info about location.
I bind service, like it is mentioned in Bind to Service section and implement using a Messenger. Next I tried to do:
Thread t = new Thread(){
public void run(){
bindService(new Intent(this, GPSLogger.class), mConnection, Context.BIND_AUTO_CREATE);
}
};
t.start();
App is working, but all the GPSLogger stuff is doing in main thread.
Is it any way to repair this?
Regular services run in main thread.
You can use IntentService instead. It is a job queue with a single bg thread.
If you insist on using the base Service class then you'll have to spawn your own threads.
I've been struggling with this question for weeks now. I'm fairly new to Android, hopefully you can give me a hand.
I have this service which runs on a separate thread than the app's. Essentially, the user instructs it to start, and it should stay alive either until the user tells it to stop or until it has served its purpose - it schedules its own destruction (stop) when needed. The service needs to stay alive as it holds important priority-related information, so I can't simply turn to the alarm manager to revive it when needed - though I do use alarm manager for other purposes. I'm having two problems:
First of all, when the user closes the application (by holding the middle button and close the app) the service is destroyed, which means, I lose my data (I'm assuming it gets destroyed as it reboots automatically).
Secondly, it restarts itself, thus causing the data to be re-loaded hence, I lose the data.
As for the activity, its binding to the server through:
private void startService() {
startService(new Intent(this, CES.class));
bindService(new Intent(this, CES.class), mConnection, 0);
}
Finally, the relevant (or at least the ones I find relevant) methods in the Service:
private final IBinder mBinder = new ICESInterface.Stub() { ..... }
#Override
public void onCreate() {
//keeps being called thus I lose my data }
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent,flags,startId);
//return START_STICKY;
}
Let me know if there is more data/information you need.
By returing a binder in onBind you are creating a bound service, which means it is "bound" to your app. This means that it get's destroyed when you app does, that explains the home button destroy. You should be returning null for a background service.
#Override
public void onCreate() {
//keeps being called thus I lose my data
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
You should start your service with START_STICKY flag, so that if the OS destroys your service when running low on resources, it will later recreate it.
Prior to destroying your service, Android will call public void onLowMemory(), there save any data you need so that when it restarts your service, you will be able to do your task again.
EDIT: As per your comment, you would like a service that is running in the background and also allows binding. You can do that if you call the startService() method before any bindService() calls are made... this will effectively make your service a started service instead of bound. In that case you are able to return a IBInder and bind to it.
There is a really, really good article HERE
In my PollFragment.java that able to call new PollTask((MainActivity)getActivity()).execute((Void)null);
And in my PollTask.java
public PollTask(MainActivity activity){
super(activity);
TerminalCfg terminalCfg = Global.getTerminalCfg();
terminalId = terminalCfg.getTerminalId();
retailerAcc = terminalCfg.getRetailerAcc();
internalId = APIUtil.getInternalId(activity);
username = APIUtil.getUsername(activity);
}
And now I want to call the new PollTask((MainActivity)getActivity()).execute((Void)null);
in MyBackgroundService with extends Service like below :
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
new PollTask((MainActivity)getActivity()).execute((Void)null);
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
Is there any other way to replace the getActivity() to call the method?
A Service is a separate component from an Activity and thus you cannot get a reference to it using getActivity(). Services are designed for doing work not visible to the user, including (but not limited to) background work on a separate thread from the UI thread. Services are more robust and offer more control over what work is being performed that is not visible to the user. They do not require an Activity to run.
An AsyncTask is a simple way of doing work from inside an Activity on a separate Thread from the UI thread.
Basically, you dont want or need an AsyncTask in a Service.
Instead, in your Service you should either spawn a Thread, or use IntentService which will handle creating a worker Thread for you. Then when you are finished, send an intent back to the Activity either by starting it or using a LocalBroadcast
Alternatively, you can tie a Service to an Activity and provide methods that the Service and Activity can call directly on each other through an IBinder interface. These are called bound services and will only be alive as long as the Activity is alive.
Try an IntentService
I think your best bet is to try learning how to use an IntentService
http://developer.android.com/reference/android/app/IntentService.html
I'm working on an Android app that needs to maintain a network connection to a chat server. I understand that I can create a service to initiate the connection to the server, but how would the service notify an Android Activity of new incoming messages? The Activity would need to update the view to show the new messages. I'm pretty new to Android, so any help is appreciated. Thanks!
Can you pass a handler to your service?
First, define your handler as an interface. This is an example, so yours may be more complex.
public interface ServerResponseHandler {
public void success(Message[] msgs); // msgs may be null if no new messages
public void error();
}
Define an instance of your handler in your activity. Since it's an interface you'll provide the implementation here in the activity, so you can reference the enclosing activity's fields and methods from within the handler.
public class YourActivity extends Activity {
// ... class implementation here ...
updateUI() {
// TODO: UI update work here
}
ServerResponseHandler callback = new ServerResponseHandler() {
#Override
public void success(Message[] msgs) {
// TODO: update UI with messages from msgs[]
YourActivity.this.updateUI();
}
#Override
public void error() {
// TODO: show error dialog here? (or handle error differently)
}
}
void onCheckForMessages() {
networkService.checkForMessages(callback);
}
and NetworkService would contain something like:
void checkForMessages(ServerResponseHandler callback) {
// TODO: contact server, check for new messages here
// call back to UI
if (successful) {
callback.success(msgs);
} else {
callback.error();
}
}
Also, as Aleadam says, you should also be away that a service runs on the same thread by default. This is often not preferred behavior for something like networking. The Android Fundamentals Page on Services explicitly warns against networking without separate threads:
Caution: A service runs in the main thread of its hosting process—the service does not
create its own thread and does not run in a separate process (unless you specify
otherwise). This means that, if your service is going to do any CPU intensive work or
blocking operations (such as MP3 playback or networking), you should create a new thread
within the service to do that work. By using a separate thread, you will reduce the
risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
For more information on using threads in your service, check out the SO articles Application threads vs Service threads and How to start service in new thread in android
Did you check the Service API page: http://developer.android.com/reference/android/app/Service.html ?
It has a couple of examples on how to interact with a Service.
The service runs on the same thread and the same Context as the Activity. Check also here: http://developer.android.com/reference/android/content/Context.html#bindService%28android.content.Intent,%20android.content.ServiceConnection,%20int%29
Finally, take a look also at Lars Vogel's article: http://www.vogella.de/articles/AndroidServices/article.html
One common and useful approach is to register a broadcast receiver in your Activity, and have the Service send out notification events when it has useful data. I find this to be easier to manage than implementing a handler via a callback, mainly because it makes it easier and safer when there is a configuration change. If you pass a direct Activity-reference to the Service then you have to be very careful to clear it when the Activity is destroyed (during rotation, or backgrounding), otherwise you get a leak.
With a Broadcast Receiver you still have to unregister when the Activity is being destroyed, however the Service never has a direct reference to the Activity so if you forget the Activity will not be leaked. It is also easier to have the Activity register to listen to a topic when it is created, since it never has to obtain a direct reference to the Service...
Lars Vogel's article discusses this approach, it is definitely worth reading! http://www.vogella.com/tutorials/AndroidServices/article.html#using-receiver