I had created music player service which stop automatically on back pressed. I want to set it continuously until songs are available or user manually close from notification window. Any help appreciated.
Here below i put some code which i had created from reference
private MediaPlayer player;
private final IBinder musicBind = new MusicBinder();
public void onCreate(){
super.onCreate();
player = new MediaPlayer();
initMusicPlayer();
}
public void initMusicPlayer(){
//set player properties
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
//set listeners
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
//activity will bind to service
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
//release resources when unbind
#Override
public boolean onUnbind(Intent intent){
//player.stop();
//player.release();
return false;
}
#Override
public void onDestroy() {
//stopForeground(true);
}
this code is used in activity to bind service
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
From above code my service is started but i'm not able to play song directly i had to click on play button
public void playSong() {
player.reset();
try {
sendName_image();
player.setDataSource(URI object);
player.prepareAsync();
} catch (Exception e) {
}
}
Above method is called on button click
you should call player.start(); to start playing after player prepared
Related
I'm creating a music player app in Android and I'm trying to set up the MediaPlayer as a service so that it persists across all Activities/Fragments. The service code:
public class PlayerService extends Service {
MediaPlayer mediaPlayer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
}
public void LoadUrl(String url){
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(url);
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
//mediaPlayer.start();
Play(mediaPlayer);
}
public void Play(MediaPlayer player) {
player.start();
}
public void Pause(MediaPlayer player) {
player.pause();
}
}
and the MainActivity:
public class MainActivity extends AppCompatActivity {
PlayerService playerService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState != null){
} else {
playerService = new PlayerService();
Intent startPlayer = new Intent(this, PlayerService.class);
startService(startPlayer);
....
When MainActivity is started, it launches the service, however, when I try to load a Url into the MediaPlayer with:
playerService.LoadUrl(feedItem.getAudioUrl());
I get an exception saying that mediaPlayer in the Service is null. How can I make sure that the mediaPlayer is retained?
You are trying to start the service using startService without onStartCommand in service, without which the sevice won't start. So your media player won't get initialized
After pressing back button on MainActivity (which calls it's onDestroy()), the media plays in the background (using foreground service).
But after opening the app again ((which calls it's onCreate()), and if I try to play another song, the first song is not stopped. Both songs play together. How do I solve this?
Any help is appreciated.
This is my MusicService class:
public void onCreate() {
super.onCreate();
Log.i(TAG3, "onCreate");
songPosn=0;
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
player = new MediaPlayer();
initMusicPlayer();
rand=new Random();
}
//initializes the MediaPlayer class
public void initMusicPlayer(){
Log.i(TAG3, "initMusicPlayer");
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public void setList(ArrayList<Song> theSongs){
songs=theSongs;
}
//We will call this when the user picks a song from the list.
public void setSong(int songIndex){
songPosn=songIndex;
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
//Let's now set the app up to play a track
public void playSong(){
Log.i(TAG3, "playSong");
player.reset();
//get song
Song playSong = songs.get(songPosn);
songTitle=playSong.getTitle();
//get id
long currSong = playSong.getID();
//set uri
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
try{
player.setDataSource(getApplicationContext(), trackUri);
}
catch(Exception e){
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
public void playPrev(){
songPosn--;
if(songPosn<0) songPosn=songs.size()-1;
playSong();
}
//skip to next
public void playNext(){
if(repeat){playSong();}
else if(shuffle){
int newSong = songPosn;
while(newSong==songPosn){
newSong=rand.nextInt(songs.size());
}
songPosn=newSong;
playSong();
}
else{
songPosn++;
if(songPosn>=songs.size()) songPosn=0;
playSong();
}
}
public int getPosn(){
return player.getCurrentPosition();
}
public int getDur(){
return dr;
}
public boolean isPng(){
return player.isPlaying();
}
public void pausePlayer(){
player.pause();
}
public void seek(int posn){
player.seekTo(posn);
}
public void go(){
player.start();
}
public void setShuffle(){
if(shuffle) shuffle=false;
else {shuffle=true;repeat=false;}
}
public void setRepeat(){
if(repeat) repeat=false;
else {repeat=true;shuffle=false;}
}
//When the MediaPlayer is prepared, the onPrepared method will be executed.
#Override
public void onPrepared(MediaPlayer mp) {
Log.i(TAG3, "onPrepared");
//start playback
mp.start();
dr = player.getDuration();
Intent notIntent = new Intent(this, MainActivity.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.play)
.setTicker(songTitle)
.setOngoing(true)
.setContentTitle("Playing").setContentText(songTitle);
Notification not = builder.build();
startForeground(NOTIFY_ID, not);
}
#Override
public void onCompletion(MediaPlayer mp) {
Log.i(TAG3, "onCompletion");
if(player.getCurrentPosition()>0){
mp.reset();
playNext();
}
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.i(TAG3, "onError");
mp.reset();
return false;
}
#Override
public void onAudioFocusChange(int focusChange) {
if(focusChange<=0) {
//LOSS -> PAUSE
player.pause();
} else {
//GAIN -> PLAY
player.start();
}
}
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG3, "onBind");
return musicBind;
}
#Override
public boolean onUnbind(Intent intent){
Log.i(TAG3, "onUnbind");
return false;
}
#Override
public void onDestroy() {
Log.i(TAG3, "onDestroy");
mAudioManager.abandonAudioFocus(this);
stopForeground(true);
}
Note; I had removed player.stop(); player.release(); from the onUnbind() since the playback gets stopped on pressing backbutton on MainActivity.
The back button should not call onDestroy when pressed.
I found it here:
https://stackoverflow.com/a/5868534/6737655
I made a simple music player which can play some songs in the background.
Going to the homescreen and reopen the app through notification works as well.
The only Problem I have is that if I press the back button(going to parent activity) in the music player activity my app crashes. There are two classes, the activity MP3Player.java and the service MP3Service.jave.
I am getting the following error:
java.lang.RuntimeException: Unable to destroy activity {package/package.MP3Player}: java.lang.IllegalArgumentException: Service not registered: package.MP3Player$1#b135b300
Do you know any advide?
Thanks in advance!
EDIT1:
I bound my player like this in my player activity:
MP3Player.java(Activity)
playIntent = new Intent(this, MP3Service.class);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
I used this tutorial and modified it.
EDIT 3:
Now I get this error:
java.lang.RuntimeException: Unable to stop service package.MP3Service#b13a6f80: java.lang.IllegalStateException
MP3Service.java
public void onCreate() {
super.onCreate();
songPosn = 0;
player = new MediaPlayer();
initMusicPlayer();
}
public void initMusicPlayer() {
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public void setList(ArrayList<Song> theSongs) {
songs = theSongs;
}
public class MusicBinder extends Binder {
MP3Service getService() {
return MP3Service.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
#Override
public boolean onUnbind(Intent intent) {
player.stop();
player.release();
return false;
}
public void playSong() {
player.reset();
Song playSong = songs.get(songPosn);
try {
player.setDataSource(getApplicationContext(),
Uri.parse(playSong.getPath()));
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
public void pauseMusic() {
if (player.isPlaying()) {
player.pause();
length = player.getCurrentPosition();
}
}
public void resumeMusic() {
if (player.isPlaying() == false) {
player.seekTo(this.length);
player.start();
} else {
Toast.makeText(getApplicationContext(),
"Please select a song to play", Toast.LENGTH_LONG).show();
}
}
public void stopMusic() {
player.stop();
player.release();
player = null;
}
// set the song
public void setSong(int songIndex) {
songPosn = songIndex;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
#Override
public void onDestroy() {
super.onDestroy();
if (player != null) {
try {
player.stop();
player.release();
} finally {
player = null;
}
}
}
MP3Player.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mp3_player);
getActionBar().setDisplayHomeAsUpEnabled(true);
songList = getSongList();
listAdapter = new PlayListAdapter(this, songList);
listMusic.setAdapter(listAdapter);
listMusic.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int pos,
long arg3) {
currentSongPos = pos;
musicSrv.setSong(currentSongPos);
musicSrv.playSong();
}
});
}
private ServiceConnection musicConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicBinder binder = (MusicBinder) service;
musicSrv = binder.getService();
musicSrv.setList(songList);
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
#Override
protected void onStart() {
super.onStart();
if (playIntent == null) {
playIntent = new Intent(this, MP3Service.class);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
}
}
...
protected void onDestroy() {
if (musicBound) {
stopService(playIntent);
unbindService(musicConnection);
musicSrv = null;
}
super.onDestroy();
}
Service not registered means it wasn't bound to service during unbindService() call.
Read about service lifecycle on : API Guide: Services
EDIT:
Try to add:
protected void onDestroy() {
if(musicBound){
stopService(playIntent);
unbindService(musicConnection);
musicSrv=null;
}
super.onDestroy();
}
EDIT 2:
Sorry my fault, you need to call first stopService() and then unbindService()
The Android documentation for stopService() states:
Note that if a stopped service still has ServiceConnection objects bound to it with the BIND_AUTO_CREATE set, it will not be destroyed
until all of these bindings are removed. See the Service documentation
for more details on a service's lifecycle.
I'm creating a music streaming app. As per android's MediaPlayer guide, I'm controlling the MediaPlayer from a Service. This all works fine and now I'm trying to add a MediaController to control playback. To do so, I'm having my Service implement MediaController.MediaPlayerControl, and having my Activity bind to my Service, and then instantiating the MediaController from the Activity with the Service context from the ServiceConnection.
Player.java
public class Player extends Activity implements OnClickListener, OnItemClickListener, MediaController.MediaPlayerControl {
private MediaController mediaController;
private ServiceConnection mConnection = 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;
mService = binder.getService();
mBound = true;
showMediaController();
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
startService(
new Intent(this, PlayerService.class)
.setAction("com.limastreamer.action.NEXTSHOW"));
bindService(
new Intent(this, PlayerService.class),
mConnection,
Context.BIND_AUTO_CREATE);
}
public void showMediaController() {
if (mBound) {
mediaController = new MediaController(this);
mediaController.setAnchorView(
findViewById(R.id.player)
);
mediaController.setMediaPlayer(mService);
mediaController.setEnabled(true);
mediaController.show(0);
}
}
}
PlayerService.java
public class PlayerService extends Service implements MediaController.MediaPlayerControl {
private MediaPlayer mMediaPlayer;
public class LocalBinder extends Binder {
PlayerService getService() {
return PlayerService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
String action = intent.getAction();
if (action.equals("com.limastreamer.action.NEXTSHOW")) {
if (mMediaPlayer == null)
{
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setLooping(false);
}
try
{
mMediaPlayer.reset();
mMediaPlayer.setDataSource(url);
mMediaPlayer.prepareAsync(); // prepare async to not block main thread
}
catch (Exception ex)
{
Toast.makeText(getApplicationContext(), "Failed to prepare MediaPlayer", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public boolean canPause() {
return true;
}
#Override
public boolean canSeekBackward() {
return true;
}
#Override
public boolean canSeekForward() {
return true;
}
#Override
public int getBufferPercentage() {
return 0;
}
#Override
public int getCurrentPosition() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying())
return mMediaPlayer.getCurrentPosition();
else
return 0;
}
#Override
public int getDuration() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying())
return mMediaPlayer.getDuration();
else
return 0;
}
#Override
public boolean isPlaying() {
if (mMediaPlayer != null)
return mMediaPlayer.isPlaying();
else
return false;
}
#Override
public void pause() {
if (mMediaPlayer != null)
mMediaPlayer.pause();
}
#Override
public void seekTo(int msec) {
if (mMediaPlayer != null)
mMediaPlayer.seekTo(msec);
}
#Override
public void start() {
if (mMediaPlayer != null)
mMediaPlayer.start();
}
}
R.id.player refers to the root element of my xml layout.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/player"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".Player" >
On calling mediaController.show(); the app bombs out with the exception: Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
From looking at other questions on SO (for example), it seems that this is caused by using the wrong context here: mediaController = new MediaController(this);, ie using something other than the Activity context. But as far as I can tell, I am using the Activity context.
I've tried:
Using other views in the layout as the anchor view (even tho the doc says you can use the Activity's main view)
Putting the MediaController in a fragment, and using getActivity() as the context, as shown here
Putting the MediaController in the xml layout instead of instantiating it programatically.
Setting a VideoView as the anchor view (some people say it only works with a VideoView).
Creating a new class that extends VideoView and implements MediaPlayerControl, and instantiating the MediaController in that class, using the saved context that was passed to the class when it was initialized as the context, and this as the anchor view.
Your activity should implement MediaPlayer.OnPreparedListener and set onPreparedListener of mediaPlayer of your service to the player activity.
public class MyMediaPlayer extends Activity implements
MediaController.MediaPlayerControl,MediaPlayer.OnPreparedListener {
...
public void onCreate(Bundle savedInstanceState) {
...
//this mediaPlayer is the reference of your media player inside your service
mediaPlayer.setOnPreparedListener(this);
...
}
...
}
also you have to start your service a little after you created your activity
Intent in=new Intent(MainPlayer.this,MyMediaPlayer.class);
startActivity(in);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//START YOUR SERVICE TO PREPARE YOUR PLAYER
this works for me.
I have a service bound to an activity. The activity is a ListView of playable files. The service plays a certain audio file, passed from the Activty. In the previous version I hadn't had the Service bind, so when clicking multiple times on a play element, multiple instances of sounds would occur. I thought I could solve this by binding the service, so I would communicate every time with the same instance, however it still plays multiple files if they are clicked. Maybe i understood the concept of binding wrong, I'm not sure, the android documentation is sometimes a bit vague and misleading. Here is my code, thanks for any input.
Activity:
public class ViewSounds extends ListActivity {
private PlayService myService;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Bind Service
Intent intent = new Intent(ViewSounds.this, PlayService.class);
getApplicationContext().bindService(intent, serviceConncetion, BIND_AUTO_CREATE);
// Get list vars
String[] lex_names = getResources().getStringArray(R.array.lex_names);
//final String[] lex_files = getResources().getStringArray(R.array.lex_files);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_sounds, lex_names));
final ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//int playFile = getResources().getIdentifier(lex_files[position], "raw", getPackageName());
myService.playAudio();
}
});
}
private ServiceConnection serviceConncetion = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
myService = ((PlayService.MyBinder)service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
myService = null;
}
};
#Override
public void onDestroy(){
super.onDestroy();
unbindService(serviceConncetion);
}
}
Service:
public class PlayService extends Service {
MediaPlayer player;
private final IBinder binder = new MyBinder();
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class MyBinder extends Binder {
PlayService getService() {
return PlayService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
}
public void playAudio(){
// I hardcoded the file name for this preview
player = MediaPlayer.create(this, R.raw.no_harm);
player.setLooping(false); // Set looping
if (!player.isPlaying()) {
player.start();
}
}
public void onStart(Intent intent, int startId){
super.onStart(intent, startId);
Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
// Get veriable from Activity
// int extras;
// extras = intent.getExtras().getInt("playFile");
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
You should stop playback of previous file before playing another file. In your code you actually creating new MediaPlayer for each new media file.
Here is how your playAudio should look like:
public void playAudio(){
// I hardcoded the file name for this preview
if(player != null){
player.release();
}
player = MediaPlayer.create(this, R.raw.no_harm);
player.setLooping(false); // Set looping
if (!player.isPlaying()) {
player.start();
}
}
But you should avoid creation of new media players for each new playback. You could do this next way:
public void playAudio(){
// I hardcoded the file name for this preview
if(player == null){
player = new MediaPlayer();
}
if(player.isPlaying()){
player.stop();
}
player.reset();
player.setLooping(false);
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener(){
#Override
void onPrepared(MediaPlayer mp){
mp.play();
}
});
player.prepareAsync();
}
You should also use onSetErrorListener(...) and onSetComlpletionListener(...) for more control over the player. So that your activity can react on state changes in MediaPlayer.