私はAndroidサービスを習得しようとしていますが、少し問題があります。バインドされたサービスのアクティビティライフサイクル
私はMediaPlayer
という簡単なサービスを持っており、インターネットからストリームを再生しています。私はMainActivity
にサービスをバインドし、サービスにURLを設定してストリームの再生を開始します。これは正常に動作します。サービスは直ちに通知を受けてフォアグラウンドサービスになります。私は首尾よくMainActivity
からURLを変更し、その後新しいストリームを開始することができます。しかし、実装したいことがいくつかあります。
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
}
}
もちろん、ウィジェットがリスナーと私のMainActivity
でありかつ選択が変更されたときstartStreaming()
方法がありますと呼ばれる。
誰でも正しい方向に向けることができますか?
アクティビティのonPauseをバインド解除し、onResumeを再バインドする必要があります。また、経験則として、 'onDestroy'の中で起こる何にも依存しない - Androidはあなたの活動を殺し、' onDestroy'は実行されないかもしれません。 – vkislicins
通知の点で - 通知を作成する前に、アクティビティがサービスにバインドされているかどうかを確認します。バインドをお持ちの場合は、通知を表示しないでください。あなたのサービスの 'onBind'または 'onRebind'の中には、通知を隠すようにしてください。 – vkislicins
@vkislicins 'onStop' /' onDestroy'の中で 'unbindService'を問題なく呼び出すことができます。' onPause'で 'unbindService'を呼び出すのは貴重ですリソースはあまりにも頻繁に呼び出すことができるようにのみ – pskink