Media player finalized before being released - android

I sometimes (not every time) get this warning "Media player finalized before being released" in LogCat, and the sound is played only partially (cuts off).
I have a service CountdownService, and there I have:
MyApplication appActivity = (MyApplication)this.getApplication();
appActivity.playCountdownComplete();
stopSelf(); // I absolutely must stop the service at this point
And in the MyApplication (extends Application) activity I have:
public void playCountdownComplete() {
MediaPlayer mp = MediaPlayer
.create(getApplicationContext(), R.raw.sound_complete);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
mp.start();
}
I absolutely must stop the service at the point where I call stopSelf(); because my app depends on the service not running, so please do not offer a solution that changes that.
Why doesn't the sound play completely? - the application activity is playing the sound, so even if the service is stopped, it shouldn't matter, right?
EDIT: I also tried having the service send out a broadcast and the Application activity receiving it and playing the sound there, but still the same thing happens.

Related

Stopping an Android service (when back to the foreground) not working

Here is an issue I am facing when using a service in an Android app to play audio in the background.
The audio plays as expected in the background, and the app has a stop button that should be used to stop the audio play when the app comes back to the foreground. And this button is not working.
I use a class instance variable serviceIntent like this:
class MainActivity : AppCompatActivity() {
.....
private var serviceIntent:Intent? = null
.....
}
Here is how the service is started from the onStop() method of the main activity.
override fun onStop() {
super.onStop()
.....
serviceIntent = Intent(this, AudioService::class.java)
serviceIntent?.let {
it.putExtra("audioPath", audioPath)
it.putExtra("timePosit", playTimeStamp.toString())
it.putExtra("playMode", playMode)
.....
startForegroundService(it)
}
}
And here is how I try to stop the service when the stop button is tapped (but this is not working):
(The two first lines are obviously only for debugging)
stopBtn.setOnClickListener {
if (serviceIntent == null) println("There is no +++serviceIntent+++")
else println("Trying to stop +++serviceIntent+++")
serviceIntent?.let {stopService(it)}
}
I can see the message: "Trying to stop +++serviceIntent+++"
indicating that serviceIntent is not null, but the audio playing does not stop.
Any relevant feedback by some more experienced user will be much appreciated.
You need to stop the audio service as well before you stop your service.if you are using audio manager try stopping like this and pass listener _audioFocusChangeListener of OnAudioFocusChangeListener interface.
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.abandonAudioFocus(_audioFocusChangeListener);

Stop Android Service when user presses the home button

I have a music service that plays music in the background of the app. I want the music to keep playing through all activities of the application but to stop when the app is running in the background (ie when the user goes to another app or presses the home button without removing the app from the running applications)
This is my MusicService code:
public class MusicService extends Service {
public static MediaPlayer player;
public IBinder onBind(Intent arg0) {
return null;
}
public int onStartCommand(Intent intent, int flags, int startId) {
player= MediaPlayer.create(this,R.raw.music1);
player.start();
player.setLooping(true);
return super.onStartCommand(intent,flags,startId);
}
}
and this is the part of my manifest related to the music service:
<service android:name=".MusicService" android:stopWithTask="true" />
Edit: If anyone knows how to play background music without service also that would be okay as long as the music plays during the whole time the app is open and closes when the home button is pressed.
Basicaly you have to define witch activity is your exit point and then edit your onStartCommand like this
private boolean playing; // use this var to determine if the service is playing
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if(action == ACTION_PLAY) {
// No each time your start an activity start the service with ACTION_PLAY but in ACTION_PLAY process check if the player if not already runing
if(!playing) {
player= MediaPlayer.create(this,R.raw.music1);
player.start();
player.setLooping(true);
// here you set playing to true
playing = true;
}
} else if(action.equals(ACTION_STOP) {
// Set playing to false
playing = false;
// This is just an exemple : Now here increase a delay little bit so that the player will not stop automaticaly after leaving activity
new Handler().postDelayed(new Runnable(){
#override
public void run() {
// No before stoping the play service
// check playing if playing dont go further
if(playing) return;
if(player!=null && player.isPlaying()) {
player.stop();
player.release();
player.reset(); // To avoid mediaPlayer has went away with unhandled error warning
player = null;
// And stop the service
stopSelf();
}
}
},2500);
}
return START_STICKY;}
Now if you want to start playing use
Intent intent = new Intent(context,YourService.class);
intent.setAction(YourService.ACTION_PLAY);
And for stopping
Intent intent = new Intent(context,YourService.class);
intent.setAction(YourService.ACTION_STOP);
And dont forget to define the two action contants fields
If you dont want to define your exit point you can define a boolean that determine that your service is in use and therefore wont be stopped by the delayed handler
Now each time one of activity start, start the service with action ACTION_PLAY
and once it stop start the service with ACTION_STOP that will ensure that each activity have the ability to start and stop player
also dont forget to tweak the delay
Hope it help
I think the best solution to this problem is to stop the music in onPause() of each Activity and start the music in onResume() of each Activity. The problem you will run into is that your music will stutter when your application switches from one Activity to another. To combat that problem, you should post a Runnable (that stops the music) to a Handler in onPause(), but post it so that it doesn't run immediately. It should be delayed for about 200 milliseconds. In onResume(), cancel the Runnable so that it does not run. This will prevent the stuttering, but stop the music 200 milliseconds after the user has pressed the HOME button.
Another option is not to use a Service, but just keep the MediaPlayer instance in your Application class. You'll still want to stop and start the music in onPause() and onResume(), but you can do it more directly by just calling some methods on your Application class. You will need to create a custom Application class that extends Application and add that to your manifest.

Service and MediaPlayer - Control screen rotation and App exit

SOLVED - See answer.
I'm dealing with an app that uses a service for playing music with the MediaPlayer class.
I'm having problem with screen rotation and when I leave the app. I lose the reference or state of the MediaPlayer object or the service itself. Been working so many hours with this that not really know what is wrong.
I start and bind to the service in Activity's onResume:
#Override
protected void onResume()
{
Intent intent=new Intent(getApplicationContext(), MusicService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
super.onResume();
}
I get the reference to the service with a ServiceConnection:
private ServiceConnection serviceConnection=new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder binder)
{
service=((MusicService.MyBinder)binder).getService();
}
public void onServiceDisconnected(ComponentName className)
{
service=null;
}
};
At this point I can call any method from my service: service.playMusic(); and works fine.
I unbind in onDestroy:
#Override
protected void onDestroy()
{
unbindService(serviceConnection);
super.onDestroy();
}
And this is my Service class:
public class MusicService extends Service
{
private final IBinder binder=new MyBinder();
private MediaPlayer player;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return Service.START_REDELIVER_INTENT;
}
#Override
public IBinder onBind(Intent intent)
{
player=MediaPlayer.create(getApplicationContext(), R.raw.tumbler);
player.setLooping(true);
player.setVolume(80, 80);
return binder;
}
public class MyBinder extends Binder
{
public MusicService getService()
{
return MusicService.this;
}
}
public void play()
{
player.start();
Log.d("MUSIC SERVICE", "play!");
}
}
So, problems are:
When I exit, the service and music keeps playing. I want to stop it. If I enter the app again, same service is launched again and the music is playing twice. I want to stop it.
When I rotate the screen, the MediaPlayer keeps playing (as I want) but I can't call anymore pause(), start() and so on because it state has changed (I get the message ' MediaPlayer﹕ pause called in state 8' and `MediaPlayer﹕ start called in state 0').
Please, need some help with this. Thanks in advance!
#Override
public IBinder onBind(Intent intent) {
player=MediaPlayer.create(getApplicationContext(), R.raw.tumbler);
player.setLooping(true);
player.setVolume(80, 80);
return binder;
}
You're re-initializing the MediaPlayer every time you bind to the service and never stopping the previous instance. Don't start the media in onBind(), wait for a command to the service to start/stop the media player. Services outlive the Activity (that's what they're designed for) so it's no surprise that it keeps playing after the Activity is destroyed. Unless you specifically told it otherwise, that's the expected behavior. If you're wanting a media player that just keeps going while the Activity is open, you might want to look into using a headless Fragment to keep a retained Fragment that can manage the MediaPlayer for you in onCreate()/onDestroy().
Well I think I got it.
I had a mess in my mind (and code) but finally it's working.
If this is not the correct way to do this, please let me know.
The first of my problems was: When the App exits the Service wasn't destroyed and the MediaPlayer was playing until I force-close the App. If I didn't force-close, on App relaunch I had 2 MediaPlayers playing simultaneously and so on.
Cause: I was not terminating my Service manually.
Solution: On Activity's onDestroy(), call unbindService() and stopService():
#Override
protected void onDestroy()
{
super.onDestroy();
unbindService(serviceConnection);
stopService(new Intent(getApplicationContext(), MusicService.class));
}
The second problem was: When the screen was rotated I lost the MediaPlayer's object reference, and music was out of control because I couldn't access the object.
Cause: Bad design. I was setting up the MediaPlayer into Service's onBind() method. Thanks to #kcoppock. He noticed that. So, when the screen was rotated, Activity's onCreate() was called and I have bindService() on it, causing the creation of the new MediaPlayer object without even cleaning up the former instance.
Solution: Just move out that code to another part that is not called automatically, and call it manually once, when the App starts, and not every time that Activity is recreated by configChanges.
So, basically that is how I fixed it, hope it may help to other users.
Cheers.

Play background music across all my activities, and stop it only when my app is not displayed

I tried one millions way, but in every way the music keeps playing when i play the HOME button of my mobile.
My last attempt was with application, but i still have the same problem.
This is my code.
public class ProvaMusica extends Application {
Intent musica_backGround;
public Background_music musicaDiBackground = new Background_music();
public void avvia(){
//this is the class where i manage mediaplayer//////////
musica_backGround=new Intent(this, Background_music.class);
startService(musica_backGround);
}
public void onDestroy(){
stopService(musica_backGround);
}
}
In my first activity i use this code to start the music
ProvaMusica appState = ((ProvaMusica)this.getApplication());
appState.avvia();
Now, what should i do to let the music play when showing other activities and make the music stops when my app is not displayed?
I WANT THE MUSIC TO KEEP PLAYING WHILE MOVING FROM AN ACTIVITY TO ANOTHER, I DON'T WANT TO STOP THE MUSIC AND THEN START IT AGAIN, WHEN A NEW ACTIVITY STARTS.
The way I do this is:
I have a singleton class that is the SoundManager.
On onPause each activity calls soundManager.stopPlayingDelayed. This method starts a timer that will call soundManager.checkIfShouldStop in 1 or 2 seconds. It also saves the lastCloseTime to the current time.
Each activity on it's onResume calls soundManager.startPlaying. If already playing the sound manager will ignore the request. This also clears the lastCloseTime
In checkIfShouldStop , if the lastCloseTime is not zero and is more than 1 second ago, it means that after the last activity finished, no new activity of my app was started, so the music should be stopped.
You can have an Application class and set it in AndroidManifest. in its onDestroy() callback, you can use stopService() function to stop the service or you can start the service with an Intent to stop the music.
Your app works as a process in the Android operating system. There are various ways for Android OS to terminate processes and sometimes callback functions like onDestroy() may not be called before the process is killed. Therefore if you start and play your music in a service, the music will play as long as your process lives. However, if you want it to stop, when a specific activity of your app is killed, you can override onDestroy() of that activity and broadcast a message for your service to stop the music. Use a service to implement this.
Maybe i found a way mixing the suggestions all of you gave me.
WITH THIS CODE THE BACKGROUND MUSIC (IN THIS CASE MANAGED WITH A SERVICE) STOPS ONLY WHEN USERS CLOSE THE APP WITH THE BACK BUTTON, WHEN USERS CLOSE THE APP WITH THE HOME BUTTON AND WHEN SCREENS TURN OFF BECAUSE USERS LOCK THE SCREEN WITH THE LOCK BUTTON OF THE DEVICES.
I'd like someone more expert and good at programming than me to confirm this is correct
in this class i check if my current activity is in foreground or not
public class GestioneApplicazioneInBackground{
public static boolean applicazioneInBackground(final Context context) {
ActivityManager am = (ActivityManager) MainActivity.context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
}
in onStop() and onPause() methods of all my activities i have this code
/// if my app and his activities are in background i stop the service i started in my main/first activity////
if(GestioneApplicazioneInBackground.applicazioneInBackground(this) ){
context_of_the_Intent.stopService(intent);
}
else{
// if my app and his activities are NOT in background i check if user turned off the screen with the lock button of the device//////
PowerManager kgMgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean showing = kgMgr.isScreenOn();
if(!showing){
context_of_the_Intent.stopService(intent);
}
}
Use this one : Tf you usr media player then Call this method in your activity...
MediaPlayer mp=null;
#Override
protected void onDestroy() {
super.onDestroy();
if (!(mp == null)) {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = null;
}
}
};
v #Override
protected void onResume() {
super.onResume();
if (!(mp == null)) {
if (mp.isPlaying()) {
mp.stop();
mp.release();
mp = null;
}
}
};

Android Google Music app stops when my intro video plays

I'm using a VideoView in my Android app to display the intro animation.
If the Google Music App is playing music in the background, calling videoview.start() stops music playing in Google Music App in the background.
Is there a way to make sure any music in the background will keep playing at the same time with my intro video? (it has no audio)
Thank you!
Turns out Google Music App and a few other apps will stop their music when any video starts playing.
In order to make sure I'm not interrupting the listening experience for my users I now skip the intro video if I determine that there is music playing in the background.
To do this:
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (am.isMusicActive()) {
loadApp(); // skip video and go straight to the app
}
else {
videoView.start(); // play video
}
Using both the answers previously given, here is a solution that will resume music after your video ends:
final boolean music_was_playing = ((AudioManager) getSystemService(Context.AUDIO_SERVICE)).isMusicActive();
VideoView vv_Video = (VideoView) findViewById(R.id.intro_video_view);
// play the intro video
vv_Video.setOnCompletionListener( new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer m) {
// resume music if it was playing cause our intro video just paused it temporarily
if (music_was_playing) {
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "play");
sendBroadcast(i);
}
// go to main menu
startActivity(new Intent(IntroActivity.this, MainMenuActivity.class));
}
});
Taken from openVideo() in VideoView.java
Intent i = new Intent("com.android.music.musicservicecommand");
i.putExtra("command", "pause");
mContext.sendBroadcast(i);

Categories

Resources