当活动被破坏时如何显示来自服务的通知

时间:2019-02-10 12:12:43

标签: android service android-notifications

在这种情况下,我要从一个在后台播放音乐的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;
    }
}

1 个答案:

答案 0 :(得分:1)

基本上,您应该重新考虑显示通知的时间。由于活动的onDestroy方法可能不会总是被调用,因此我希望在显示通知时使用另一点。您还应该注意自Android 8(API 26)起的新restrictions regarding background services,如果您未将 mark 明确地标记为前台服务,则它们可能会被操作系统杀死,而应用程序在后台。

因此,出于您的目的,可以选择使用带有通知ID的方法startForeground并在活动进入后台(例如onStop)时调用它,然后它将显示通知(这是将服务保持在前台的要求)。如果您决定在一段时间后恢复活动,可以致电stopForeground停止前台模式并关闭通知。