Search code examples
androidserviceandroid-mediaplayerforeground

Members from classes that extend Service


My application has 3 activities (MainPageActivity, FavoritesActivity, SettingsActivity) and one service (StreamService).

Both MainPageActivity and FavoritesActivity have two buttons docked at the bottom: one to play/stop a stream (an internet radio), and one to favorite the current song. Both of these worked fine when the respective activities handled the music controls, but I decided to move those to a class that extends Service, since it's common practice for music players. Here are some code snippets:

MainPageActivity:

public void play (View v)
{
    Intent intent = new Intent(MainPageActivity.this, EdenService.class);
    if (!service.isPlaying())
    {
        startService(intent);
        btnPlay.setText("Stop");
    }
    else
    {
        stopService(intent);
        btnPlay.setText("Play");
    }
}

public void fave (View v)
{
    try
    {
        String currentSong = txtCurrentSong.getText().toString();
        if (!db.alreadyFavorited(currentSong))
        {
            if (!currentSong.isEmpty() || !currentSong.equals("Unavailable"))
            {
                db.addAnonymousFavorite(currentSong);
                Toast.makeText(getApplicationContext(), "Song has been added to favorites.", Toast.LENGTH_LONG).show();
                btnFave.setText("Unfave");
            }
            else
                Toast.makeText(getApplicationContext(), "Song title cannot be empty.", Toast.LENGTH_LONG).show();
        }
        else
        {
            try
            {
                db.removeAnonymousFavorite(currentSong);
                Toast.makeText(getApplicationContext(), "Song has been removed from favorites.", Toast.LENGTH_LONG).show();
                btnFave.setText("Fave");
            }
            catch (Exception e)
            {
                Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
            }
        }
    }
    catch (Exception e)
    {
        Toast.makeText(getApplicationContext(), "Could not add song to favorites.", Toast.LENGTH_LONG).show();
        Log.e("playButton", Log.getStackTraceString(e));
    }
}

//used in onResume for navigation within the app
    private void setPlayButtonText()
    {
        if (!service.isPlaying())
            btnPlay.setText("Play");
        else
            btnPlay.setText("Stop");
    }

private void setFaveButtonText()
{
    runnable = new Runnable() {
        @Override
        public void run() {
            final String currentSong = ServiceHandler.getCurrentSong();
            if (!Settings.isAuthenticated(getApplicationContext()))
            {
                if (!db.alreadyFavorited(currentSong))
                    btnFave.setText("Fave");
                else
                    btnFave.setText("Unfave");
                handler.postDelayed(this, 3000);
            }
        }
    };
runnable.run();
}

FavoritesActivity has the same code.

StreamService:

public StreamService()
{
    this.mp = new MediaPlayer();
    isPlaying = false;
}

@Override
public void onCreate ()
{
    try
    {
        mc = new MediaController(this);
        mp.setDataSource(streamLink);
        mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mc.setMediaPlayer(this);
        mp.prepareAsync();
        Log.d(TAG + ".onCreate()", Boolean.toString(isPlaying));
    }
    catch (Exception e)
    {
        Log.e(TAG, Log.getStackTraceString(e));
        Toast.makeText(getApplicationContext(), "Could not connect to stream.", Toast.LENGTH_LONG).show();
    }
}

@Override
public void onDestroy()
{
    pause();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    isPlaying = true;
    new Thread(new Runnable()
    {
        @Override
        public void run() {
            start();
        }
    }).start();

    return Service.START_STICKY;
}

@Override
public void start() {
    try
    {
        mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            public void onPrepared(MediaPlayer mp) {
                mp.start();
            }
        });
        mp.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mediaPlayer, int what, int extra) {
                String errorText = "";
                switch (what) {
                    //what = 1
                    case MediaPlayer.MEDIA_ERROR_UNKNOWN:
                        errorText += "Error has occured: ";
                        break;
                    //what = 100
                    case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                        errorText += "Server has died. ";
                        break;
                }

                switch (extra) {
                    //extra = -1004
                    case MediaPlayer.MEDIA_ERROR_IO:
                        errorText += "Please check your internet connection.";
                        break;
                    //extra = -110
                    case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
                        errorText += "Connection has timed out.";
                        break;
                }
                Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show();
                return true;
            }
        });

        Intent intent = new Intent(this, MainPageActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);

        Notification notification = new NotificationCompat.Builder(getApplicationContext())
                .setContentTitle("Eden Radio")
                .setContentText(ServiceHandler.getCurrentSong())
                .setSmallIcon(R.drawable.ic_stat_av_play)
                .setContentIntent(pi).build();
        startForeground(CLASS_ID, notification);

    }
    catch (Exception e)
    {
        Log.e(TAG, e.getMessage());
        Toast.makeText(getApplicationContext(), "Could not connect to stream.", Toast.LENGTH_LONG).show();
    }
}

@Override
public void pause() {
    mp.stop();
    stopForeground(true);
    isPlaying = false;
}

    @Override
public boolean isPlaying() {
    //mp.isPlaying() always returns false for some reason
    return isPlaying; //and so does this
}

Now, my question is: service.isPlaying() always returns false, so when I press play and the music starts, but I can never stop the music. Why is that? I've tried making a singleton out of the service (and found out while trying that Service in of itself is a singleton, though I'm still not sure how that works), I've tried making the isPlaying field and its corresponding method isPlaying() static, but to no avail. Accessing to MainPageActivity through the notification issued when the stream is playing, through other activities, and through destroying and restarting the application just causes play button to reinitialise to "Play", and never being able to stop the stream. Same thing happens in FavoritesActivity.

I've spent far too much time trying to figure out why it never returns the right value. I'd greatly appreciate it if you could help me.

Thanks in advance.


Solution

  • Bind that service to your activities in onResume(). This will create service once and then allow you to interact with it. You may find some documents on how to bind the service and interact with it here:

    Bound Services