2016-03-22 8 views
0

私は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()方法がありますと呼ばれる。

誰でも正しい方向に向けることができますか?

+0

アクティビティのonPauseをバインド解除し、onResumeを再バインドする必要があります。また、経験則として、 'onDestroy'の中で起こる何にも依存しない - Androidはあなたの活動を殺し、' onDestroy'は実行されないかもしれません。 – vkislicins

+0

通知の点で - 通知を作成する前に、アクティビティがサービスにバインドされているかどうかを確認します。バインドをお持ちの場合は、通知を表示しないでください。あなたのサービスの 'onBind'または 'onRebind'の中には、通知を隠すようにしてください。 – vkislicins

+0

@vkislicins 'onStop' /' onDestroy'の中で 'unbindService'を問題なく呼び出すことができます。' onPause'で 'unbindService'を呼び出すのは貴重ですリソースはあまりにも頻繁に呼び出すことができるようにのみ – pskink

答えて

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()サービスが実行中であるかどうかを確認し、再作成する代わりに再バインドしてください。実行していない場合は作成してバインドします。

関連する問題