gpt4 book ai didi

java - 通过绑定(bind)的前台服务保持音频播放

转载 作者:行者123 更新时间:2023-12-01 21:29:53 25 4
gpt4 key购买 nike

我正在研究绑定(bind)服务、前台服务以及如何使用它们进行音频播放。

基于this example我已经设置了一个前台服务来播放音频。这非常适合我的用例,直到我尝试绑定(bind)服务,因为我需要在 Activity 和服务之间来回传递一些数据,例如我想要实现的搜索栏的播放位置。

我浏览了几篇 StackOverflow 帖子,试图找到解决方案。我知道我应该在启动服务之前绑定(bind)该服务,这样它就不会与它所绑定(bind)的 Activity 一起被杀死。但一旦我添加了绑定(bind)机制,这仍然会发生。

当我将设备置于 sleep 状态时,这是我在 logcat 中看到的唯一错误:

2019-11-12 10:49:24.553 812-871/? W/InputDispatcher: channel '7fc2cb2 com.example.android.meditationhub/com.example.android.meditationhub.ui.PlayActivity (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
2019-11-12 10:49:24.553 812-871/? E/InputDispatcher: channel '7fc2cb2 com.example.android.meditationhub/com.example.android.meditationhub.ui.PlayActivity (server)' ~ Channel is unrecoverably broken and will be disposed!

所以,我需要找出 channel 被破坏的原因,但目前我很困惑还能去哪里寻找。 ...

这是我当前的 PlayActivity 设置:

//called from onCreate()
private void initializeUI() {
playerBinding.playbackControlBt.setPlayListener(new AnimatePlayButton.OnButtonsListener() {
@Override
public boolean onPlayClick(View view) {
mediaPlayerServiceInt = new Intent(PlayActivity.this, MediaPlayerService.class);
mediaPlayerServiceInt.setAction(Constants.START_ACTION);
mediaPlayerServiceInt.putExtra(Constants.URI, medUri);
startService(mediaPlayerServiceInt);
bindMediaPlayerService();
return true;
}

@Override
public boolean onPauseClick(View view) {
Intent pausePlayback = new Intent(PlayActivity.this, MediaPlayerService.class);
pausePlayback.setAction(Constants.PAUSE_ACTION);
PendingIntent pendingPausePlayback = PendingIntent.getService(PlayActivity.this,
0, pausePlayback, PendingIntent.FLAG_UPDATE_CURRENT);
try {
pendingPausePlayback.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
return true;
}

@Override
public boolean onResumeClick(View view) {
Intent resumePlayback = new Intent(PlayActivity.this, MediaPlayerService.class);
resumePlayback.setAction(Constants.PLAY_ACTION);
PendingIntent pendingResumePlayback = PendingIntent.getService(PlayActivity.this,
0, resumePlayback, PendingIntent.FLAG_UPDATE_CURRENT);
try {
pendingResumePlayback.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
return true;
}

@Override
public boolean onStopClick(View view) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
stopService(mediaPlayerServiceInt);
}
return true;
}
});
}

//monitor state of the service
private ServiceConnection mediaPlayerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mediaPlayerService = ((MediaPlayerService.MyBinder) service).getService();
serviceIsBound = true;
}

@Override
public void onServiceDisconnected(ComponentName name) {
mediaPlayerService = null;
serviceIsBound = false;
}
};

//unbind service so the audio continues to play
private void unbindMediaPlayerService() {
unbindService(mediaPlayerConnection);
serviceIsBound = false;
Timber.v("Service unbound");
}

//bind service so the display can follow the audio playback
private void bindMediaPlayerService() {
if (!serviceIsBound) {
Intent bindInt = new Intent(this, MediaPlayerService.class);
serviceIsBound = bindService(bindInt, mediaPlayerConnection, Context.BIND_AUTO_CREATE);
Timber.v("Service bound");
} else {
Timber.v("no Service to bind");
}
}

@Override
protected void onStart() {
super.onStart();
if (MediaPlayerService.getState() != Constants.STATE_NOT_INIT) {
bindMediaPlayerService();
}
@Override
protected void onStop() {
super.onStop();
if (MediaPlayerService.getState() != Constants.STATE_NOT_INIT) {
unbindMediaPlayerService();
}
}
}

还有MediaPlayerService :

// Binder given to Activity
private final IBinder binder = new MyBinder();

/**
* Class used for the client Binder. The Binder object is responsible for returning an instance
* of {@link MediaPlayerService} to the client.
*/
public class MyBinder extends Binder {
public MediaPlayerService getService() {
// Return this instance of MyService so clients can call public methods
return MediaPlayerService.this;
}
}

@Override
public IBinder onBind(Intent arg0) {
return binder;
}

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

stateService = Constants.STATE_NOT_INIT;
notMan = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {

if (intent == null || intent.getAction() == null) {
stopForeground(true);
stopSelf();
return START_NOT_STICKY;
}

switch (intent.getAction()) {
case Constants.START_ACTION:
if(intent.getExtras() != null) {
medUri = (Uri) intent.getExtras().get(Constants.URI);
}
stateService = Constants.STATE_PREPARE;

startForeground(Constants.NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
destroyPlayer();
initPlayer();
play();
break;

case Constants.PAUSE_ACTION:
stateService = Constants.STATE_PAUSE;
notMan.notify(Constants.NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
destroyPlayer();
handler.postDelayed(delayedShutdown, Constants.DELAY_SHUTDOWN_FOREGROUND_SERVICE);
break;

case Constants.PLAY_ACTION:
stateService = Constants.STATE_PREPARE;
notMan.notify(Constants.NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
destroyPlayer();
initPlayer();
play();
break;

case Constants.STOP_ACTION:
Timber.i("Received Stop Intent");
destroyPlayer();
stopForeground(true);
stopSelf();
break;

default:
stopForeground(true);
stopSelf();
}
return START_NOT_STICKY;
}

@Override
public void onDestroy() {
Timber.d("onDestroy()");
destroyPlayer();
stateService = Constants.STATE_NOT_INIT;
try {
timerUpdateHandler.removeCallbacksAndMessages(null);
} catch (Exception e) {
e.printStackTrace();
}
super.onDestroy();
}

您可以在 GitHub 上找到链接的完整代码。

目的是允许用户在收听时将设备置于 sleep 状态,或者让它自行进入休眠状态。服务的绑定(bind)是必要的,以便在设备打开或 Activity 进入前台时显示播放进度(通过搜索栏和计数器)。

我哪里出错了或者我忽略了什么?或者我应该考虑更好的方法?预先感谢您的任何指示和帮助。

预计到达时间:我已切换到未过滤的 logCat 并发现了一个新错误。我将开始粘贴保存外状态且未绑定(bind)服务的位置。

2019-11-14 09:57:42.942 8326-8326/com.example.android.meditationhub V/PlayActivity: all outstates saved
2019-11-14 09:57:42.943 8326-8326/com.example.android.meditationhub V/PlayActivity: all outstates saved
2019-11-14 09:57:42.944 8326-8326/com.example.android.meditationhub V/PlayActivity: all outstates saved
2019-11-14 09:57:42.950 8326-8326/com.example.android.meditationhub V/PlayActivity: Service unbound
2019-11-14 09:57:42.951 8326-8326/com.example.android.meditationhub V/PlayActivity: Service unbound
2019-11-14 09:57:42.953 225-1957/? I/BufferQueueProducer: [ColorFade](this:0xaab2a000,id:5867,api:1,p:812,c:225) new GraphicBuffer needed
2019-11-14 09:57:42.954 225-1957/? I/[MALI][Gralloc]: usage1: 0xf02, format: 1 stride: 720 vertical_stride: 1280 size: 3686400
2019-11-14 09:57:42.954 8326-8326/com.example.android.meditationhub V/PlayActivity: Service unbound
2019-11-14 09:57:42.955 225-1957/? D/GraphicBuffer: alloc, handle(0xac1921e0) (w:720 h:1280 s:720 f:0x1 u:0x000f02) err(0)
2019-11-14 09:57:42.958 812-859/? D/GraphicBuffer: register, handle(0x88e7d160) (w:720 h:1280 s:720 f:0x1 u:0x000f02)
2019-11-14 09:57:42.979 225-369/? I/BufferQueueProducer: [ColorFade](this:0xaab2a000,id:5867,api:1,p:812,c:225) new GraphicBuffer needed
2019-11-14 09:57:42.979 225-369/? I/[MALI][Gralloc]: usage1: 0xf02, format: 1 stride: 720 vertical_stride: 1280 size: 3686400
2019-11-14 09:57:42.980 225-369/? D/GraphicBuffer: alloc, handle(0xac1922a0) (w:720 h:1280 s:720 f:0x1 u:0x000f02) err(0)
2019-11-14 09:57:42.983 812-859/? D/GraphicBuffer: register, handle(0x88e789a0) (w:720 h:1280 s:720 f:0x1 u:0x000f02)
2019-11-14 09:57:42.994 812-3148/? D/PowerManagerNotifier: onWakeLockReleased: flags=1, tag="ActivityManager-Sleep", packageName=android, ownerUid=1000, ownerPid=812, workSource=null
2019-11-14 09:57:42.995 258-748/? D/Sunwave: sw_sensor 896:send cancel sem
2019-11-14 09:57:42.995 258-747/? I/Sunwave: sw-hal 281:irq canceled!
2019-11-14 09:57:42.995 258-747/? D/Sunwave: IC8221 1237:wait irq cancel
2019-11-14 09:57:42.995 258-747/? D/Sunwave: IC8221 712:soft reset
2019-11-14 09:57:42.998 258-733/? D/Sunwave: sw_sensor 225:irq receive wake, but g_bIrqEnable = 0
2019-11-14 09:57:43.000 258-747/? D/Sunwave: IC8221 2573:warning: fp irq canceled
2019-11-14 09:57:43.005 258-747/? D/Sunwave: FpFinger 2405:keyFinger cancel:1
2019-11-14 09:57:43.006 812-859/? D/DisplayPowerController: ABC configure: enabledInDoze=false, lowDimmingProtectionEnabled=false, adjustment=0.7919922, state=2, brightness=-1
2019-11-14 09:57:43.006 812-859/? D/AutomaticBrightnessController: getAutomaticScreenBrightness: brightness=255, dozing=false, factor=1.0
2019-11-14 09:57:43.007 812-859/? D/DisplayPowerController: Unfinished business...
2019-11-14 09:57:43.023 8326-8849/com.example.android.meditationhub D/FA: Logging event (FE): user_engagement(_e), Bundle[{ga_event_origin(_o)=auto, engagement_time_msec(_et)=5780, ga_screen_class(_sc)=PlayActivity, ga_screen_id(_si)=7992583200822585152}]
2019-11-14 09:57:43.024 8326-8326/com.example.android.meditationhub E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 895384)
2019-11-14 09:57:43.025 8326-8326/com.example.android.meditationhub D/AndroidRuntime: Shutting down VM
2019-11-14 09:57:43.026 943-943/? D/SystemServicesProxy: getTopMostTask: tasks: 2600

--------- beginning of crash
2019-11-14 09:57:43.027 8326-8326/com.example.android.meditationhub E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.meditationhub, PID: 8326
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 895384 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3865)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: android.os.TransactionTooLargeException: data parcel size 895384 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:622)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3708)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3857)
at android.os.Handler.handleCallback(Handler.java:836) 
at android.os.Handler.dispatchMessage(Handler.java:103) 
at android.os.Looper.loop(Looper.java:203) 
at android.app.ActivityThread.main(ActivityThread.java:6251) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924) 
2019-11-14 09:57:43.034 812-1424/? W/ActivityManager: Force finishing activity com.example.android.meditationhub/.ui.PlayActivity

“交易太大”似乎是关键,但我对什么交易感到困惑。因为我还没有在服务和 Activity 之间进行沟通。我开始怀疑服务中的timerUpdateHandler。当设备进入休眠状态时,我是否也应该停止通知?

最佳答案

问题不在于服务绑定(bind),而在于 OnSavedInstanceState,它触发了 TansactionTooLargeException。我将在这里提供我的解决方案,因为我怀疑其他人也可能遇到这个问题。

我需要重新训练 Activity 的任何数据都会传达给服务。服务立即需要的内容通过启动它的 Intent 传递。就我而言,这是音频 Uri 和标题。

 mediaPlayerServiceInt = new Intent(PlayActivity.this, MediaPlayerService.class);
mediaPlayerServiceInt.setAction(Constants.START_ACTION);
mediaPlayerServiceInt.putExtra(Constants.URI, medUri);
mediaPlayerServiceInt.putExtra(Constants.TITLE, selectedMed.getTitle());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(mediaPlayerServiceInt);
} else {
startService(mediaPlayerServiceInt);
}
bindMediaPlayerService();

当我解除绑定(bind)时, Activity 需要在 UI 中显示的任何其他数据都会传递给服务。在我的例子中,coverArt 和所选对象 (selectedMed) 包含要显示的更多信息。

 //unbind service so the audio continues to play
private void unbindMediaPlayerService() {
mediaPlayerService.setCoverArt(coverArt);
mediaPlayerService.setSelectedMed(selectedMed);

unbindService(mediaPlayerConnection);
serviceIsBound = false;
Log.v(TAG, "Service unbound");
}

非常感谢@greeble31,您回顾了所有可能性和尝试,帮助我将问题归结为根本原因!

关于java - 通过绑定(bind)的前台服务保持音频播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58816713/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com