使用绑定的前台服务保持音频播放
Keep audio playing with bound foreground service
我正在研究绑定服务、前台服务以及如何使用它们进行音频播放。
基于this example我设置了一个前台服务来播放音频。在我尝试绑定服务之前,这非常适合我的用例,因为我需要在 Activity 和服务之间来回传递一些数据,例如我要实现的搜索栏的播放位置。
我浏览了几篇 Whosebug 帖子,试图找到解决方案。我明白我应该在启动服务之前绑定它,这样它就不会连同它绑定的 Activity 一起被杀死。但这仍然会发生,只要我包含绑定机制。
当我让设备进入睡眠状态时,这是我在 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!
所以,我需要弄清楚频道被破坏的原因,但目前我不知道还能去哪里看。 …
这是我当前的 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();
}
}
}
// 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 上找到链接中的完整代码。
目的是让用户在收听时让他们的设备进入睡眠状态,或者让它自行进入睡眠状态。服务的绑定是必要的,以便在设备打开或 activity 被带到前台时显示播放进度(通过搜索栏和计数器)。
我哪里出错了或者我忽略了什么?或者我应该考虑更好的方法吗?在此先感谢您的指点和帮助。
预计到达时间:
我切换到未过滤的 logCat 并发现了一个新错误。我将开始粘贴保存外州和未绑定服务的位置。
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
"Transaction too large" 好像是key,但是我很纳闷是什么交易。因为我还没有在服务和 activity 之间进行通信。我开始怀疑服务中的 timerUpdateHandler
。当设备进入睡眠状态时,我是否也应该停止通知?
问题不在于服务绑定,而在于触发 TansactionTooLargeException
的 OnSavedInstanceState
。我会在这里提供我的解决方案,因为我怀疑其他人也可能 运行 遇到这个问题。
我需要为 Activity 重新训练的任何数据都会传送给服务。服务立即需要的是通过启动它的意图传递的。在我的例子中是音频 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();
Activity 需要在 UI 中显示的任何其他数据在我解除绑定时传递给服务。在我的例子中,coverArt 和 selected Object (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,感谢他仔细研究了所有的可能性和尝试,帮助我找到了根本原因!
我正在研究绑定服务、前台服务以及如何使用它们进行音频播放。
基于this example我设置了一个前台服务来播放音频。在我尝试绑定服务之前,这非常适合我的用例,因为我需要在 Activity 和服务之间来回传递一些数据,例如我要实现的搜索栏的播放位置。
我浏览了几篇 Whosebug 帖子,试图找到解决方案。我明白我应该在启动服务之前绑定它,这样它就不会连同它绑定的 Activity 一起被杀死。但这仍然会发生,只要我包含绑定机制。
当我让设备进入睡眠状态时,这是我在 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!
所以,我需要弄清楚频道被破坏的原因,但目前我不知道还能去哪里看。 …
这是我当前的 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();
}
}
}
// 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 上找到链接中的完整代码。
目的是让用户在收听时让他们的设备进入睡眠状态,或者让它自行进入睡眠状态。服务的绑定是必要的,以便在设备打开或 activity 被带到前台时显示播放进度(通过搜索栏和计数器)。
我哪里出错了或者我忽略了什么?或者我应该考虑更好的方法吗?在此先感谢您的指点和帮助。
预计到达时间: 我切换到未过滤的 logCat 并发现了一个新错误。我将开始粘贴保存外州和未绑定服务的位置。
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
"Transaction too large" 好像是key,但是我很纳闷是什么交易。因为我还没有在服务和 activity 之间进行通信。我开始怀疑服务中的 timerUpdateHandler
。当设备进入睡眠状态时,我是否也应该停止通知?
问题不在于服务绑定,而在于触发 TansactionTooLargeException
的 OnSavedInstanceState
。我会在这里提供我的解决方案,因为我怀疑其他人也可能 运行 遇到这个问题。
我需要为 Activity 重新训练的任何数据都会传送给服务。服务立即需要的是通过启动它的意图传递的。在我的例子中是音频 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();
Activity 需要在 UI 中显示的任何其他数据在我解除绑定时传递给服务。在我的例子中,coverArt 和 selected Object (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,感谢他仔细研究了所有的可能性和尝试,帮助我找到了根本原因!