【问题标题】:Activity lifecycle with bound service绑定服务的活动生命周期
【发布时间】:2016-03-22 16:02:11
【问题描述】:

我正在尝试学习 Android 服务,但遇到了一些麻烦。

我有一个简单的服务,MediaPlayer 可以播放来自互联网的一些流。我将服务绑定到我的MainActivity,在服务上设置一个 URL 并开始播放流。这工作正常。该服务立即成为带有通知的前台服务。我可以成功地从 MainActivity 更改 URL,然后开始一个新的流。但是,有几件事我想实现。

MainActivity 对用户可见时,我不希望收到通知,只有当用户按下主页按钮或返回按钮时,我才希望服务开始在前台播放。当用户单击通知时,我希望 MainActivity 重新打开并且流不会中断。这是否意味着我的MainActivity 永远不会被破坏?

截至目前,当我按下主页按钮时,流继续播放,单击通知会使MainActivity 重新创建服务(流停止并再次开始播放)。我实际上希望服务永远不会停止播放,除非用户通过在多任务窗口中滑动来终止应用程序(就像 Spotify 那样)。

我的服务代码如下:

public class StreamService extends Service implements
    MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
    MediaPlayer.OnCompletionListener {

    private MediaPlayer player;
    private final IBinder musicBind = new StreamBinder();
    private StreamInfo mCurrentStream;
    private static final int NOTIFY_ID = 1;

    public void onCreate() {
        super.onCreate();
        initMusicPlayer();
    }

    public void initMusicPlayer() {
        player = new MediaPlayer();
        player.setWakeMode(getApplicationContext(),
            PowerManager.PARTIAL_WAKE_LOCK);
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        player.setOnPreparedListener(this);
        player.setOnCompletionListener(this);
        player.setOnErrorListener(this);
    }

    public class StreamBinder extends Binder {
        public StreamService getService() {
            return StreamService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return musicBind;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        player.stop();
        player.release();
        return false;
    }

    public void playStream() {
        player.reset();
        try {
            player.setDataSource(this, mCurrentStream.getUrl());
        } catch (Exception e) {
            Log.e("MUSIC SERVICE", "Error setting data source", e);
        }
        player.prepareAsync();
    }

    public void setStream(StreamInfo stream) {
        mCurrentStream = stream;
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        mp.reset();
        return false;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mp.start();
        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.ic_action_navigation_chevron_right)
            .setTicker(mCurrentStream.getTitle())
            .setOngoing(true)
            .setContentTitle("Playing")
            .setContentText(mCurrentStream.getTitle());
        Notification not = builder.build();
        startForeground(NOTIFY_ID, not);
    }

    @Override
    public void onDestroy() {
        stopForeground(true);
    }
}

还有我的MainActivity

public class MainActivity extends AppCompatActivity implements ServiceConnection {

    private static final String TAG = MainActivity.class.getSimpleName();

    private StreamService mStreamService;
    private boolean musicBound = false;
    private Intent playIntent;

    @Override
    protected void onStart() {
        super.onStart();
        if (playIntent == null) {
            playIntent = new Intent(this, StreamService.class);
            bindService(playIntent, this, MainActivity.BIND_AUTO_CREATE);
            startService(playIntent);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startStreaming();
    }


    private void startStreaming() {
        mStreamService.setStream(getSelectedStream());
        mStreamService.playStream();
    }

    @Override
    protected void onDestroy() {
        stopService(playIntent);
        mStreamService = null;
        super.onDestroy();
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        StreamService.StreamBinder binder = (StreamService.StreamBinder) service;
        mStreamService = binder.getService();
        musicBound = true;
        startStreaming();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        musicBound = false;
    }

    public StreamInfo getSelectedStream() {
        //Returns some stream from a widget
    }
}

Of course there is a widget in my MainActivity with a listener and when the selection changes the startStreaming() method is called.

谁能指出我正确的方向?

【问题讨论】:

  • 您应该取消绑定您的活动onPause 并重新绑定onResume。此外,根据经验,不要依赖 onDestroy 内部发生的任何事情 - Android 可以终止您的活动,onDestroy 可能不会被执行。
  • 在通知方面 - 在创建通知之前检查您是否有绑定到服务的活动。如果您有绑定 - 不要显示通知。同样在您的服务的“onBind”或“onRebind”中,确保隐藏通知
  • @vkislicins 你可以在onStop / onDestroyunbindService 没有问题:在onPause 中调用unbindService 只是浪费宝贵的资源,因为它可能被频繁调用
  • @pskink 好点,谢谢

标签: java android android-activity service lifecycle


【解决方案1】:

当 MainActivity 对 用户,仅当用户按下我想要的主页按钮或返回按钮时 服务开始在前台播放。

在您的服务中保留一个布尔标志,以指示是否绑定了某些东西。在显示通知之前检查标志。比如:

@Override
public IBinder onBind(Intent intent) {
    mBound = true;
    hideNotifications();
    return musicBind;
}

@Override
public void onRebind(Intent intent) {
    mBound = true;
    hideNotifications();
}

当用户点击 在通知上,我希望 MainActivity 重新打开并且流 不间断。这是否意味着我的 MainActivity 永远不会被销毁?

您需要取消绑定您的活动onStop()

到目前为止,当我按下主页按钮时,流会继续播放并且 单击通知会使 MainActivity 重新创建服务 (流停止并再次开始播放)。我其实想要 服务永远不会停止播放,除非用户通过刷卡杀死应用程序 它在多任务窗口中(就像 Spotify 一样)。

onStart() 的 Activity 检查服务是否正在运行并重新绑定到它而不是重新创建它。如果它没有运行 - 创建并绑定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 2015-08-11
    • 2013-01-13
    • 2011-12-18
    相关资源
    最近更新 更多