【问题标题】:Members from classes that extend Service扩展服务的类的成员
【发布时间】:2023-07-09 22:13:01
【问题描述】:

我的应用程序有 3 个活动(MainPageActivityFavoritesActivitySettingsActivity)和一个服务(StreamService)。

MainPageActivityFavoritesActivity 底部都有两个按钮:一个用于播放/停止流(网络收音机),另一个用于收藏当前歌曲。当各自的活动处理音乐控件时,这两个都工作得很好,但我决定将它们移到扩展 Service 的类中,因为这是音乐播放器的常见做法。 下面是一些sn-ps的代码:

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 具有相同的代码。

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
}

现在,我的问题是:service.isPlaying() 总是返回 false,所以当我按下播放键时音乐开始播放,但我永远无法停止音乐。为什么会这样?我已经尝试从服务中创建一个单例(并在尝试 Service 时发现它本身就是一个单例,尽管我仍然不确定它是如何工作的),我我尝试制作isPlaying 字段及其对应的方法isPlaying()static,但无济于事。通过流播放时发出的通知、通过其他活动以及通过销毁和重新启动应用程序访问MainPageActivity 只会导致播放按钮重新初始化为“播放”,并且永远无法停止流。同样的事情发生在FavoritesActivity

我花了太多时间试图弄清楚为什么它永远不会返回正确的值。如果您能帮助我,我将不胜感激。

提前致谢。

【问题讨论】:

    标签: android service android-mediaplayer foreground


    【解决方案1】:

    将该服务绑定到 onResume() 中的活动。这将创建一次服务,然后允许您与之交互。您可以在这里找到一些关于如何绑定服务并与之交互的文档:

    Bound Services

    【讨论】:

    • 在开始从事服务工作之前,我做了一些研究,但显然不明白它们如何运作得很好。 This excellent example 清除了我之前的所有疑虑。效果很好。