I've created a music service for my application (a music player), and after making some tests I'm observing a behaviour that's causing me a headache as I don't know how to solve it.
For testing purposes, I've modified the service so, as soon as it's started, it plays a specific mp3 file from my sd card. Also, I've modified the application so the first activity is started, it starts the service, and then it calls "finish()".
Ok, so... I launch the application, and the first activity starts, my service starts and plays the music, the activity finishes and the application is closed and... the music is stopped and after some seconds the service is restarted (I'm using the START_STICKY flag, so I suppose that's normal).
I don't want the music to be stopped when I close the application, or in another words, I don't want the service to be stopped (and then restarted because it's been stopped) when my application is closed.
Right now, to control the music service, I start the service and then I bind to it so I can call the service functions I've defined in an interface.
Any ideas?
Thanks!
EDIT:
This is an example of what my application and service do (in the tests I'm doing).
Activity:
public class FirstActivity extends SherlockFragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(this, MyService.class));
...
// Here is a postDelayed that will run after 2 seconds and call finish()
}
}
Service:
public class MyService extends Service {
private MediaPlayer mPlayer;
#Override
public void onCreate() {
mPlayer = new MusicPlayer(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Here is the code that plays the music using MediaPlayer
return START_STICKY;
}
}
do not forget to put that the service is remote in your manifest application tag:
<service
android:name="somepackage.PlayerService"
android:label="Player Service"
android:process=":remote"/>
Note, that the remote name can be something else, so you can have more than one services that are not bound to the main application process
Related
My Android app is playing audio while the app runs in the background with a service that runs as foreground, similar to many other apps such as Google Play Music, Spotify, and other music players / podcast player apps.
Most apps I checked, including Google Play Music, will leave the service running even when the app is cleared from recent. On the other hand, some will stop the audio and close the service (I only found Spotify doing that).
I am wondering what is the right way to handle this? Although most apps leave the service open, it seems that users will expect the audio to stop and the notification to disappear from the status bar together with the app.
Is there a right way here?
You can check this link to see what happens to the process when app is removed from
recents list.
Even if onTaskRemoved() is called, the app is not killed in this case. The service continues to exist. It can be proven by going to the hidden developer menu to check running processes.
You can execute some codes in this callback method, and get the desired behaviour.
Since it's a question of opinion, I'm going to give my own as a developer but also a power smartphone user (well, who isn't nowadays):
tl;dr: leave it running
===============================
longer version
The point of using your phone as a music player, is providing you with audio while you're doing other activities, like running, browsing, texting, or even playing music for others connected through a speaker, being the "dj" of your group. You would rarely use a music player as a primary task and I would expect to do that when you're doing something like trying to figure out the lyrics, or watch the videoclip (and hence, you would use YouTube). Thus, it is my belief that your music player should have a separate lifecycle than the rest of your phone activities. Imagine the nightmare of playing music for others and music suddenly stops while you're messing with unrelated stuff on your phone.
However, you have a point when mentioning that "it seems that users will expect the audio to stop and the notification to disappear from the status bar together with the app". I wouldn't get the whole statement as true, rather extract the gist: users want to stop their music app easily.
In that sense, you should make it as easy as possible to stop playback to optimize your user experience. Out of the top of my head, I would imagine the best way of doing that would be a nice "X" button in your notification extended (or even when compact) version. The user then can stop the playback right from the status bar and not have to go through bringing the app to the front.
If you do want to go a step further, you could have an option in your settings to either use a foreground or background service -to make it easier for the user to understand, you could use wording like "stop music when recent apps are cleared", hence delegating the choice to your user, according to their needs. That, of course, would add complexity and too much power to your users so it's up to you to figure out if you need it.
Leave it running, with a notification.
It's all in the name.
According to Android Developers,
"The Recents screen (also referred to as the Overview screen, recent
task list, or recent apps) is a system-level UI that lists recently
accessed activities and tasks."
Swiping the task away from this list just removes it from the list, not from execution.
Notifications (Certainly under Oreo) are where you let your user know that you still have service(s) running. Use the notification to allow them to re-open the task, and then terminate the service as they see fit.
You are making like music player application, so most of the time user expected that music will be played even if the application is closed from the recent task. Now you are using foreground service so notification will be shown, in this notification you provide STOP button, so the user can stop music from there.
But if you want that your app's background service is stopped after removing from recent task then,
public class CustomService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
//stop service
stopService(new Intent(this, CustomService.class));
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("CustomService", "Service Destroyed");
}
}
Now declare service in AndroidMenifest.xml
<service android:name=".CustomService" android:stopWithTask="false" />
android:stopWithTask="false" will give callback on onTaskRemoved(), so handle stop service over there.
leave the service running when the app is cleared from recent ,user can stop completely the audio and the service in the notification with a button just like this :
Here is a picture -> QQ Music
public class OnClearFromRecentService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("ClearFromRecentService", "Service Started");
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("ClearFromRecentService", "Service Destroyed");
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.e("ClearFromRecentService", "END");
//Code here
stopSelf();
}
}
Register this service in Manifest.xml like this
<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />
Then start this service on your activity
startService(new Intent(getBaseContext(), OnClearFromRecentService.class));
And now whenever you will clear your app from android recent Then this method onTaskRemoved() will execute.
I have a countdown timer, that starts when user Logged In. After 10 Minutes it Logged Out User.
It works fine, but if user stops application, then timer stops working, and user is logged in forever.
So i put this whole thing in a service, so that it will work, either user stops application or not.
The problem is that, this has stopped working after adding Countdown Timer in Service. I have checked it on debug mode, and its not going into the service- onCreate method.
This is how i am calling the service.
startService(new Intent(this,LogoutService.class));
My Service Class, calls the CountdownTimer Class, first this code was written in the place where i write startService() now
public class LogoutService extends Service {
#Override
public void onCreate() {
UserLoggedInTimer logoutTimer= new UserLoggedInTimer(60000,1000);
logoutTimer.setContext(getApplicationContext());
logoutTimer.start();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
The countdown timer works perfectly fine when i call it without service, but here its just not getting into the service, i hope it will work fine, once my application starts the above service successfully.
put it in onStartCommand() and make it return START_STICKY
refer to this
I would like to develop a media player for Android on my own but I have a conception issue : should I use a Service or an Activity just for the player?
I have Fragments in my App and I would like to play a song when I click on one of the items within my music lists but I don't really know which of those 2 technologies I should use to allow music to keep playing even during navigation or outside the app.
Does it better to start a new Activity when a song is played and then keep the Activity running or launch a Service waiting for some events?
Thanks in advance.
The best solution for your app may be
i) Visualize your app with frontend ( like selecting music to play, pause, forward and other features )
ii) start service that runs in background which continues the activity process in background even if the activity is closed ..
You can accomplish this by implementing following ->
public class MyService extends Service implements MediaPlayer.OnPreparedListener {
private static final String ACTION_PLAY = "com.example.action.PLAY";
MediaPlayer mMediaPlayer = null;
public int onStartCommand(Intent intent, int flags, int startId) {
...
if (intent.getAction().equals(ACTION_PLAY)) {
mMediaPlayer = ... // initialize it here
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.prepareAsync(); // prepare async to not block main thread
}
}
/** Called when MediaPlayer is ready */
public void onPrepared(MediaPlayer player) {
player.start();
}
}
I think this is somehow helpful to you ..
If you want music playing in background, you should definitely use Service. Use activity only for UI-related operations. Since playing music is not UI-related operation, it should be done in Service. Please take a look here: http://developer.android.com/guide/topics/media/mediaplayer.html
I have a service that gets started (not bound) by an activity. If the activity gets destroyed (e.g. by pressing the back button), the service continues to run, this is of course intended.
However, if I swipe the activity out of the 'recent apps' list, the service gets restarted immediately. This is reproducible, every time the activity/app is swiped out of the list, there is a new call to the service's onCreate-method. No call to onDestroy in between!
First I thought the service gets killed by android, even though I saw no reason for the kill (neither the activity nor the service do resource consuming things, in fact they are minimalistic and do nothing). But then I noticed that the service actually crashes.
V/MainActivity(856): onDestroy // swipe out of the list
I/ActivityManager(287): Killing 856:com.example.myapp/u0a10050: remove task
W/ActivityManager(287): Scheduling restart of crashed service com.example.myapp/.TestService in 5000ms
The code is not noteworthy, but here it is
Activity:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v(TAG, "onCreate, starting service...");
startService(new Intent(this, TestService.class));
}
#Override
protected void onStart() {
super.onStart();
Log.v(TAG, "onStart");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG, "onDestroy");
}
//[...]
}
Service:
public class TestService extends Service {
private static final String TAG = "Service";
// onBind omitted
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v(TAG, "onDestroy");
}
}
In short:
My service is independent of the activity's lifecycle, but only as long as I don't swipe out the app of the recent apps list. In that case, the service gets restarted but without a call to onDestroy.
Every time this happens, not only the state of the service, but also the work the service is doing is lost. I just want to know why the swipe is the reason for this.
Swiping the app from the recent tasks list actually kills the operating system process that hosts the app. Since your service is running in the same process as your activities, this effectively kills the service. It does NOT call onDestroy() on the service. It just kills the process. Boom. Dead. Gone. Your service does not crash.
Since your service returned START_STICKY from the call to onStartCommand(), Android recognizes that your service should be restarted and schedules a restart of the killed service. However, when your service is restarted it will be in a newly created process (you can see onCreate() called in the service), so it will have to start the work all over again.
Rule #1: Don't ever swipe apps from the recent tasks list ;-)
Maybe it can be a problem with Broadcast receivers defined in the manifest.
Do you have some receiver / intent-filter defined in your manifest at application level ? I used to have same kind of problem and it was due to receiver declared in the manifest at the application level
By swiping, your process is NOT guaranteed to be killed by the system get killed. No. You only remove the applciation task (or back stack). Application task is NOT equal to the application process.
So if you have any background jobs (threads, services etc) tied to your back stack and you have a good cancellation policy. The system may try to cache your process if it's suitable for later.
If you kill the app process(es) from the Task Manager though, then it means that your process will be removed and so your JVM/sandbox aggressively by the system.
Use *START_NOT_STICKY* as onStartCommand return
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "onStartCommand");
return START_NOT_STICKY;
}
I have a service with a BroadcastReceiver which communicates with the activity through the method "exampleMethod()". This service start and work correctly but after a while it is stopped by Android and I have to restart it. it is possible to make sure that the service is not stopped for a long time?
public class SMS_Service extends Service{
private BroadcastReceiver rec_sms = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MainActivity.exampleMethod();
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
after a while Service is stopped by Android
The first thing that matters is that why your service is stopped by the android system,
When the user is directly interacting with a component of that process (that is an activity) Android will try very hard to keep that process running, and you won't see it killed except under extraordinary circumstances.
If it is due to low memory, then nothing could be done. When killing something for memory, the entire process (including the application object) is killed and no code executed in it at this point.
If the service is just being destroyed because it no longer needs to run, its onDestroy() will be called and when the service is later needed a new instance is created and onCreate() called.
Is it possible to make sure that the service is not stopped for a long
time?
This is not possible. The closest you can get is via startForeground(), but not even that guarantees that your service will live forever.
Moreover, this is a serious anti-pattern in Android. Users hate applications that try to run forever, which is why we have to contend with task killers and the like.