java - 停止播放音频/广播并取消返回主屏幕的通知控制,音乐停止,通知停止,前台服务不起作用

标签 java android audio stream android-notifications

大家好,我正在制作广播流应用程序,我遇到了问题。当我按返回按钮进入手机的主屏幕时,它将停止播放并消失通知,但当我通过按主按钮进行播放并返回主屏幕时,它将运行良好并继续显示通知。 我想显示通知控件并继续播放,甚至返回或销毁应用程序,直到从通知停止按钮停止为止... 通知中有2个按钮(播放/停止)。请帮助我实现这一目标...谢谢
This is my app on play store..

这是我的服务类别

public class MyService extends Service implements Player.EventListener, AudioManager.OnAudioFocusChangeListener {

    public static final String ACTION_PLAY = "action_play";
    public static final String ACTION_PAUSE = "action_pause";
    public static final String ACTION_STOP = "action_stop";

    private final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
    private MediaControllerCompat.TransportControls transportControls;
    private final IBinder iBinder = new LocalBinder();
    private NotifyClass notifyClass;
    private TelephonyManager telephonyManager;
    private MediaSessionCompat mediaSession;
    private boolean isOnGoingCall = false;
    private WifiManager.WifiLock wifiLock;
    public static SimpleExoPlayer exoPlayer;
    private AudioManager audioManager;
    private String strLiveBroadcast;
    private String myAppName;
    private Handler mHandler;
    private String streamUrl;
    private String status;
    private boolean isExoNull;

    public class LocalBinder extends Binder {
        public MyService getService() {
            return MyService.this;
        }
    }

    private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            pause();
        }
    };

    private PhoneStateListener phoneStateListener = new PhoneStateListener() {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {

            if(state == TelephonyManager.CALL_STATE_OFFHOOK
                    || state == TelephonyManager.CALL_STATE_RINGING){

                if(!isPlaying()) return;

                isOnGoingCall = true;
                stop();

            } else if (state == TelephonyManager.CALL_STATE_IDLE){

                if(!isOnGoingCall) return;

                isOnGoingCall = false;
                resume();
            }
        }
    };

    private MediaSessionCompat.Callback mediasSessionCallback = new MediaSessionCompat.Callback() {
        @Override
        public void onPause() {
            super.onPause();
            pause();
        }

        @Override
        public void onStop() {
            super.onStop();
            stop();
            notifyClass.cancelNotify();
        }

        @Override
        public void onPlay() {
            super.onPlay();
            resume();
        }
    };

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

    @Override
    public void onCreate() {
        super.onCreate();

        myAppName = getResources().getString(R.string.app_name);
        strLiveBroadcast = getResources().getString(R.string.notify_h1);

        isOnGoingCall = false;
        isExoNull = true;
        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        notifyClass = new NotifyClass(this);

        wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
                .createWifiLock(WifiManager.WIFI_MODE_FULL, "mcScPAmpLock");

        mediaSession = new MediaSessionCompat(this, getClass().getSimpleName());
        transportControls = mediaSession.getController().getTransportControls();
        mediaSession.setActive(true);
        mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mediaSession.setMetadata(new MediaMetadataCompat.Builder()
                .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "...")
                .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, myAppName)
                .putString(MediaMetadataCompat.METADATA_KEY_TITLE, strLiveBroadcast)
                .build());
        mediaSession.setCallback(mediasSessionCallback);

        telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

        mHandler = new Handler();
        exoPlayer = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), new DefaultTrackSelector());
        exoPlayer.addListener(this);

        registerReceiver(becomingNoisyReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));

        status = HandlerPlay.IDLE;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MediaButtonReceiver.handleIntent(mediaSession, intent);
        String action = intent.getAction();

        if(TextUtils.isEmpty(action))
            return START_NOT_STICKY;

        int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        if(result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED){

            stop();
            return START_NOT_STICKY;
        }

        if(action.equalsIgnoreCase(ACTION_PLAY)){
            transportControls.play();

        } else if(action.equalsIgnoreCase(ACTION_PAUSE)) {

            transportControls.pause();

        } else if(action.equalsIgnoreCase(ACTION_STOP)){

            transportControls.stop();

        }

        return START_NOT_STICKY;
    }

    @Override
    public boolean onUnbind(Intent intent) {

        if(status.equals(HandlerPlay.IDLE))
            stopSelf();

        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(final Intent intent) {

    }

    @Override
    public void onDestroy() {
        pause();
        if (!isExoNull) {
            if (exoPlayer != null) {
                exoPlayer.release();
                exoPlayer.removeListener(this);
                exoPlayer = null;
            }
            isExoNull = true;
        }
        if(telephonyManager != null)
            telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);

        notifyClass.cancelNotify();

        mediaSession.release();

        unregisterReceiver(becomingNoisyReceiver);

        super.onDestroy();
    }
    @Override
    public void onAudioFocusChange(int focusChange) {

        switch (focusChange) {
            case AudioManager.AUDIOFOCUS_GAIN:

                exoPlayer.setVolume(0.8f);

                resume();

                break;

            case AudioManager.AUDIOFOCUS_LOSS:

                stop();

                break;

            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:

                if (isPlaying()) pause();

                break;

            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:

                if (isPlaying())
                    exoPlayer.setVolume(0.1f);

                break;
        }

    }

    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

        switch (playbackState) {
            case Player.STATE_BUFFERING:
                status = HandlerPlay.LOADING;
                break;
            case Player.STATE_ENDED:
                status = HandlerPlay.STOPPED;
                break;
            case Player.STATE_IDLE:
                status = HandlerPlay.IDLE;
                break;
            case Player.STATE_READY:
                status = playWhenReady ? HandlerPlay.PLAYING : HandlerPlay.PAUSED;
                break;
            default:
                status = HandlerPlay.IDLE;
                break;
        }

        if(!status.equals(HandlerPlay.IDLE))
            notifyClass.startNotify(status);

        EventBus.getDefault().post(status);
    }

    @Override
    public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {

    }

    @Override
    public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {

    }

    @Override
    public void onLoadingChanged(boolean isLoading) {

    }

    @Override
    public void onPlayerError(ExoPlaybackException error) {

        EventBus.getDefault().post(HandlerPlay.ERROR);
    }

    @Override
    public void onRepeatModeChanged(int repeatMode) {

    }

    @Override
    public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {

    }

    @Override
    public void onPositionDiscontinuity(int reason) {

    }

    @Override
    public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {

    }

    @Override
    public void onSeekProcessed() {

    }

    public void play(String streamUrl) {

        this.streamUrl = streamUrl;

        if (wifiLock != null && !wifiLock.isHeld()) {

            wifiLock.acquire();

        }

//        DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory(getUserAgent());

        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this, getUserAgent(), BANDWIDTH_METER);

        ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
                .setExtractorsFactory(new DefaultExtractorsFactory())
                .createMediaSource(Uri.parse(streamUrl));

        exoPlayer.prepare(mediaSource);
        exoPlayer.setPlayWhenReady(true);
    }

    public void resume() {

        if(streamUrl != null)
            play(streamUrl);
    }

    public void pause() {

        exoPlayer.setPlayWhenReady(false);

        audioManager.abandonAudioFocus(this);
        wifiLockRelease();
    }

    public void stop() {

        exoPlayer.stop();

        audioManager.abandonAudioFocus(this);
        wifiLockRelease();
    }

    public void playOrPause(String url){

        if(streamUrl != null && streamUrl.equals(url)){

            if(!isPlaying()){

                play(streamUrl);

            } else {

                pause();
            }

        } else {

            if(isPlaying()){

                pause();

            }

            play(url);
        }
    }

    public String getStatus(){

        return status;
    }

    public MediaSessionCompat getMediaSession(){

        return mediaSession;
    }

    public boolean isPlaying(){

        return this.status.equals(HandlerPlay.PLAYING);
    }

    private void wifiLockRelease(){

        if (wifiLock != null && wifiLock.isHeld()) {

            wifiLock.release();
        }
    }

    private String getUserAgent(){

        return Util.getUserAgent(this, getClass().getSimpleName());
    }
}

以下是通知类

public class NotifyClass {

    public static final String PRIMARY_CHANNEL = "PRIMARY_CHANNEL_ID";
    public final String PRIMARY_CHANNEL_NAME = "PRIMARY";
    private NotificationManagerCompat notificationManager;
    public static final int NOTIFICATION_ID = 555;
    private Resources resources;
    private MyService service;
    public NotifyClass(MyService service) {
        this.service = service;
        this.resources = service.getResources();

        notificationManager = NotificationManagerCompat.from(service);
    }
    public void startNotify(String playbackStatus) {

        Bitmap largeIcon = BitmapFactory.decodeResource(resources, R.drawable.radio_icon_light);

        int icon = R.drawable.ic_pause_white;
        Intent playbackAction = new Intent(service, MyService.class);
        playbackAction.setAction(MyService.ACTION_PAUSE);
        PendingIntent action = PendingIntent.getService(service, 1, playbackAction, 0);

        if(playbackStatus.equals(HandlerPlay.PAUSED)){

            icon = R.drawable.exo_notification_play;
            playbackAction.setAction(MyService.ACTION_PLAY);
            action = PendingIntent.getService(service, 2, playbackAction, 0);

        }

        Intent stopIntent = new Intent(service, MyService.class);
        stopIntent.setAction(MyService.ACTION_STOP);
        PendingIntent stopAction = PendingIntent.getService(service, 3, stopIntent, 0);

        Intent intent = new Intent(service, MainActivity.class);
        intent.setAction(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent pendingIntent = PendingIntent.getActivity(service, 0, intent, 0);

        notificationManager.cancel(NOTIFICATION_ID);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            NotificationChannel channel = new NotificationChannel(PRIMARY_CHANNEL, PRIMARY_CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_LOW);
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);

            NotificationManager manager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }

        NotificationCompat.Builder builder = new NotificationCompat.Builder(service, PRIMARY_CHANNEL)
                .setOngoing(true)
                .setAutoCancel(false)
                .setContentTitle(PLAY_NAME)
                .setContentText(PLAY_FRQ)
                .setLargeIcon(largeIcon)
                .setContentIntent(pendingIntent)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setSmallIcon(R.drawable.radio_small)
                .addAction(icon, "pause", action)
                .addAction(R.drawable.exo_notification_stop, "stop", stopAction)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setWhen(System.currentTimeMillis())
                .setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
                        .setMediaSession(service.getMediaSession().getSessionToken())
                        .setShowActionsInCompactView(0, 1)
                        .setShowCancelButton(true)
                        .setCancelButtonIntent(stopAction));

        service.startForeground(NOTIFICATION_ID, builder.build());
    }

    public void cancelNotify() {

        service.stopForeground(true);
    }

}

下面是Handler类

public class HandlerPlay {

    public static final String IDLE = "Radio_IDLE";

    public static final String LOADING = "Radio_LOADING";

    public static final String PLAYING = "Radio_PLAYING";

    public static final String PAUSED = "Radio_PAUSED";

    public static final String STOPPED = "Radio_STOPPED";

    public static final String ERROR = "Radio_ERROR";
}

以下是 list

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xxx.xxx.xxx">

    <permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:name=".util.AppController"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
        <activity android:name=".ChatActivity"
            android:label="Live Chat"
            android:theme="@style/ChatBackground"
            android:screenOrientation="portrait"/>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:configChanges="orientation|screenSize"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity android:name=".PrivacyPolicy" />
        <activity
            android:name=".SplashActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.SplashScreen">
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchconfig" />

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name="androidx.media.session.MediaButtonReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
        </receiver>

        <service android:name=".services.MyService">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
        </service>

        <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />
    </application>

</manifest>

最佳答案

这是Logcat

2020-02-03 12:53:16.410 7356-7356/com.dpstudio.hamronepaliradio E/ActivityThread: Activity com.dpstudio.hamronepaliradio.MainActivity has leaked ServiceConnection com.dpstudio.hamronepaliradio.services.HandlerRadio$1@d208636 that was originally bound here
    android.app.ServiceConnectionLeaked: Activity com.dpstudio.hamronepaliradio.MainActivity has leaked ServiceConnection com.dpstudio.hamronepaliradio.services.HandlerRadio$1@d208636 that was originally bound here
        at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:1719)
        at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:1611)
        at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:1748)
        at android.app.ContextImpl.bindService(ContextImpl.java:1701)
        at android.content.ContextWrapper.bindService(ContextWrapper.java:711)
        at com.dpstudio.hamronepaliradio.services.HandlerRadio.bind(HandlerRadio.java:49)
        at com.dpstudio.hamronepaliradio.fragments.AllFragment.onResume(AllFragment.java:243)
        at androidx.fragment.app.Fragment.performResume(Fragment.java:2747)
        at androidx.fragment.app.FragmentStateManager.resume(FragmentStateManager.java:363)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1197)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2617)
        at androidx.fragment.app.FragmentManager.dispatchResume(FragmentManager.java:2581)
        at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:269)
        at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:478)
        at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:467)
        at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:195)
        at android.app.Activity.performResume(Activity.java:7583)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4000)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4040)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7045)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
2020-02-03 12:53:16.454 7356-7356/com.dpstudio.hamronepaliradio D/EventBus: No subscribers registered for event class java.lang.String
2020-02-03 12:53:16.455 7356-7356/com.dpstudio.hamronepaliradio D/EventBus: No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
2020-02-03 12:53:16.460 7356-7356/com.dpstudio.hamronepaliradio I/ExoPlayerImpl: Release 933984b [ExoPlayerLib/2.10.1] [greatlte, SM-G950F, samsung, 28] [goog.exo.core]
2020-02-03 12:53:16.462 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] signalFlush
2020-02-03 12:53:16.462 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] ExecutingState flushing now (codec owns 10/10 input, 0/5 output).
2020-02-03 12:53:16.463 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] Now Flushing
2020-02-03 12:53:16.463 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] FlushingState onOMXEvent(0,1,0)
2020-02-03 12:53:16.463 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] FlushingState onOMXEvent(0,1,1)
2020-02-03 12:53:16.463 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] Now Executing
2020-02-03 12:53:16.467 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] Now Executing->Idle
2020-02-03 12:53:16.471 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] Now Idle->Loaded
2020-02-03 12:53:16.472 7356-7459/com.dpstudio.hamronepaliradio I/ACodec: [OMX.SEC.mp3.dec] Now Loaded
2020-02-03 12:53:16.472 7356-7459/com.dpstudio.hamronepaliradio I/ACodec:  [OMX.SEC.mp3.dec] Now kWhatShutdownCompleted event : 8544
2020-02-03 12:53:16.475 7356-7459/com.dpstudio.hamronepaliradio I/ACodec:  [OMX.SEC.mp3.dec] Now uninitialized
2020-02-03 12:53:16.476 7356-7459/com.dpstudio.hamronepaliradio I/ACodec:  [] Now kWhatShutdownCompleted event : 8544
2020-02-03 12:53:16.476 7356-7459/com.dpstudio.hamronepaliradio I/MediaCodec: Codec shutdown complete

关于java - 停止播放音频/广播并取消返回主屏幕的通知控制,音乐停止,通知停止,前台服务不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60014459/

相关文章:

javac 1.8.0_45 和 javac 1.8.0_92 之间的 Java 类型推断差异?

java - java量词 "?"如何工作?

安卓 : start activity from background service

java - android中super关键字的使用

android - 尝试在 Android 中添加帐户时出现异常

java - 动态地将Java线程转换为openCL内核

java - 避免不在 FX 应用程序线程上导致 UI 崩溃

audio - 自定义主题中的Tumblr新音频播放器

audio - SoundCloud,通过 api 下载或流式传输文件

jquery - 使用jQuery滚动静音静音