在这种情况下,我要从一个在后台播放音乐的Activity中启动服务。当我在此活动上按后退按钮时,活动将被销毁。但服务仍在后台运行。我想在此活动销毁时向用户显示通知,以便他们可以播放/暂停/停止通知中的音频。但是我不希望在服务启动时显示通知。
下面是我的活动代码:
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class PlayBackgroundAudioActivity extends AppCompatActivity {
private AudioServiceBinder audioServiceBinder = null;
private Handler audioProgressUpdateHandler = null;
// Show played audio progress.
private ProgressBar backgroundAudioProgress;
private TextView audioFileUrlTextView;
// This service connection object is the bridge between activity and background service.
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// Cast and assign background service's onBind method returned iBander object.
audioServiceBinder = (AudioServiceBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_background_audio);
setTitle("dev2qa.com - Play Audio Use Background Service");
// Bind background audio service when activity is created.
bindAudioService();
final String audioFileUrl = "http://www.dev2qa.com/demo/media/test.mp3";
backgroundAudioProgress = (ProgressBar)findViewById(R.id.play_audio_in_background_service_progressbar);
// Get audio file url textview.
audioFileUrlTextView = (TextView)findViewById(R.id.audio_file_url_text_view);
if(audioFileUrlTextView != null)
{
// Show web audio file url in the text view.
audioFileUrlTextView.setText("Audio File Url. \r\n" + audioFileUrl);
}
// Click this button to start play audio in a background service.
Button startBackgroundAudio = (Button)findViewById(R.id.start_audio_in_background);
startBackgroundAudio.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Set web audio file url
audioServiceBinder.setAudioFileUrl(audioFileUrl);
// Web audio is a stream audio.
audioServiceBinder.setStreamAudio(true);
// Set application context.
audioServiceBinder.setContext(getApplicationContext());
// Initialize audio progress bar updater Handler object.
createAudioProgressbarUpdater();
audioServiceBinder.setAudioProgressUpdateHandler(audioProgressUpdateHandler);
// Start audio in background service.
audioServiceBinder.startAudio();
backgroundAudioProgress.setVisibility(ProgressBar.VISIBLE);
Toast.makeText(getApplicationContext(), "Start play web audio file.", Toast.LENGTH_LONG).show();
}
});
// Click this button to pause the audio played in background service.
Button pauseBackgroundAudio = (Button)findViewById(R.id.pause_audio_in_background);
pauseBackgroundAudio.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
audioServiceBinder.pauseAudio();
Toast.makeText(getApplicationContext(), "Play web audio file is paused.", Toast.LENGTH_LONG).show();
}
});
// Click this button to stop the media player in background service.
Button stopBackgroundAudio = (Button)findViewById(R.id.stop_audio_in_background);
stopBackgroundAudio.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
audioServiceBinder.stopAudio();
backgroundAudioProgress.setVisibility(ProgressBar.INVISIBLE);
Toast.makeText(getApplicationContext(), "Stop play web audio file.", Toast.LENGTH_LONG).show();
}
});
}
// Bind background service with caller activity. Then this activity can use
// background service's AudioServiceBinder instance to invoke related methods.
private void bindAudioService()
{
if(audioServiceBinder == null) {
Intent intent = new Intent(PlayBackgroundAudioActivity.this, AudioService.class);
// Below code will invoke serviceConnection's onServiceConnected method.
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
}
// Unbound background audio service with caller activity.
private void unBoundAudioService()
{
if(audioServiceBinder != null) {
unbindService(serviceConnection);
}
}
@Override
protected void onDestroy() {
// Unbound background audio service when activity is destroyed.
unBoundAudioService();
super.onDestroy();
}
// Create audio player progressbar updater.
// This updater is used to update progressbar to reflect audio play process.
private void createAudioProgressbarUpdater()
{
/* Initialize audio progress handler. */
if(audioProgressUpdateHandler==null) {
audioProgressUpdateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// The update process message is sent from AudioServiceBinder class's thread object.
if (msg.what == audioServiceBinder.UPDATE_AUDIO_PROGRESS_BAR) {
if( audioServiceBinder != null) {
// Calculate the percentage.
int currProgress =audioServiceBinder.getAudioProgress();
// Update progressbar. Make the value 10 times to show more clear UI change.
backgroundAudioProgress.setProgress(currProgress*10);
}
}
}
};
}
}
@Override
public void onBackPressed() {
startActivity(new Intent(PlayBackgroundAudioActivity.this,ForeGroundService.class));
finish();
}
}
以下是我的服务代码:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class AudioService extends Service {
private AudioServiceBinder audioServiceBinder = new AudioServiceBinder();
public AudioService() {
}
@Override
public IBinder onBind(Intent intent) {
return audioServiceBinder;
}
}
下面是myaudio活页夹类:
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import java.io.IOException;
/**
* Created by Jerry on 2/15/2018.
*/
public class AudioServiceBinder extends Binder {
// Save local audio file uri ( local storage file. ).
private Uri audioFileUri = null;
// Save web audio file url.
private String audioFileUrl = "";
// Check if stream audio.
private boolean streamAudio = false;
// Media player that play audio.
private MediaPlayer audioPlayer = null;
// Caller activity context, used when play local audio file.
private Context context = null;
// This Handler object is a reference to the caller activity's Handler.
// In the caller activity's handler, it will update the audio play progress.
private Handler audioProgressUpdateHandler;
// This is the message signal that inform audio progress updater to update audio progress.
public final int UPDATE_AUDIO_PROGRESS_BAR = 1;
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
public String getAudioFileUrl() {
return audioFileUrl;
}
public void setAudioFileUrl(String audioFileUrl) {
this.audioFileUrl = audioFileUrl;
}
public boolean isStreamAudio() {
return streamAudio;
}
public void setStreamAudio(boolean streamAudio) {
this.streamAudio = streamAudio;
}
public Uri getAudioFileUri() {
return audioFileUri;
}
public void setAudioFileUri(Uri audioFileUri) {
this.audioFileUri = audioFileUri;
}
public Handler getAudioProgressUpdateHandler() {
return audioProgressUpdateHandler;
}
public void setAudioProgressUpdateHandler(Handler audioProgressUpdateHandler) {
this.audioProgressUpdateHandler = audioProgressUpdateHandler;
}
// Start play audio.
public void startAudio()
{
initAudioPlayer();
if(audioPlayer!=null) {
audioPlayer.start();
}
}
// Pause playing audio.
public void pauseAudio()
{
if(audioPlayer!=null) {
audioPlayer.pause();
}
}
// Stop play audio.
public void stopAudio()
{
if(audioPlayer!=null) {
audioPlayer.stop();
destroyAudioPlayer();
}
}
// Initialise audio player.
private void initAudioPlayer()
{
try {
if (audioPlayer == null) {
audioPlayer = new MediaPlayer();
if (!TextUtils.isEmpty(getAudioFileUrl())) {
if (isStreamAudio()) {
audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
audioPlayer.setDataSource(getAudioFileUrl());
} else {
audioPlayer.setDataSource(getContext(), getAudioFileUri());
}
audioPlayer.prepare();
// This thread object will send update audio progress message to caller activity every 1 second.
Thread updateAudioProgressThread = new Thread()
{
@Override
public void run() {
while(true)
{
// Create update audio progress message.
Message updateAudioProgressMsg = new Message();
updateAudioProgressMsg.what = UPDATE_AUDIO_PROGRESS_BAR;
// Send the message to caller activity's update audio prgressbar Handler object.
audioProgressUpdateHandler.sendMessage(updateAudioProgressMsg);
// Sleep one second.
try {
Thread.sleep(1000);
}catch(InterruptedException ex)
{
ex.printStackTrace();
}
}
}
};
// Run above thread object.
updateAudioProgressThread.start();
}
}catch(IOException ex)
{
ex.printStackTrace();
}
}
// Destroy audio player.
private void destroyAudioPlayer()
{
if(audioPlayer!=null)
{
if(audioPlayer.isPlaying())
{
audioPlayer.stop();
}
audioPlayer.release();
audioPlayer = null;
}
}
// Return current audio play position.
public int getCurrentAudioPosition()
{
int ret = 0;
if(audioPlayer != null)
{
ret = audioPlayer.getCurrentPosition();
}
return ret;
}
// Return total audio file duration.
public int getTotalAudioDuration()
{
int ret = 0;
if(audioPlayer != null)
{
ret = audioPlayer.getDuration();
}
return ret;
}
// Return current audio player progress value.
public int getAudioProgress()
{
int ret = 0;
int currAudioPosition = getCurrentAudioPosition();
int totalAudioDuration = getTotalAudioDuration();
if(totalAudioDuration > 0) {
ret = (currAudioPosition * 100) / totalAudioDuration;
}
return ret;
}
}
答案 0 :(得分:1)
基本上,您应该重新考虑显示通知的时间。由于活动的onDestroy方法可能不会总是被调用,因此我希望在显示通知时使用另一点。您还应该注意自Android 8(API 26)起的新restrictions regarding background services,如果您未将 mark 明确地标记为前台服务,则它们可能会被操作系统杀死,而应用程序在后台。
因此,出于您的目的,可以选择使用带有通知ID的方法startForeground并在活动进入后台(例如onStop)时调用它,然后它将显示通知(这是将服务保持在前台的要求)。如果您决定在一段时间后恢复活动,可以致电stopForeground停止前台模式并关闭通知。