我已经在我的spotifyclone应用程序中实现了音乐服务,但是当我运行项目时,我得到了以下异常
java.lang.RuntimeException: Unable to create service com.example.spotifyclone.exoplayer.MusicService: java.lang.IllegalArgumentException
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3610)
at android.app.ActivityThread.access$1500(ActivityThread.java:206)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1716)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6820)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
Caused by: java.lang.IllegalArgumentException
at com.google.android.exoplayer2.util.Assertions.checkArgument(Assertions.java:39)
at com.google.android.exoplayer2.ui.PlayerNotificationManager$Builder.<init>(PlayerNotificationManager.java:353)
at com.example.spotifyclone.exoplayer.MusicNotificationManager.<init>(MusicNotificationManager.kt:33)
at com.example.spotifyclone.exoplayer.MusicService.onCreate(MusicService.kt:71)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:3598)
低于我的MusicService.kt
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import androidx.media.MediaBrowserServiceCompat
import com.example.spotifyclone.exoplayer.callbacks.MusicPlaybackPreparer
import com.example.spotifyclone.exoplayer.callbacks.MusicPlayerEventListener
import com.example.spotifyclone.exoplayer.callbacks.MusicPlayerNotificationListener
import com.example.spotifyclone.other.Constants.MEDIA_ROOT_ID
import com.example.spotifyclone.other.Constants.NETWORK_ERROR
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.*
import javax.inject.Inject
private const val SERVICE_TAG = "MusicService"
@AndroidEntryPoint
class MusicService : MediaBrowserServiceCompat() {
@Inject
lateinit var dataSourceFactory: DefaultDataSourceFactory
@Inject
lateinit var exoPlayer: ExoPlayer
@Inject
lateinit var firebaseMusicSource: FirebaseMusicSource
private val serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)
private lateinit var mediaSession: MediaSessionCompat
private lateinit var mediaSessionConnector: MediaSessionConnector
var isForegroundService = false
private var curPlayingSong: MediaMetadataCompat? = null
private lateinit var musicNotificationManager: MusicNotificationManager
private var isPlayerInitialized = false
private lateinit var musicPlayerEventListener: MusicPlayerEventListener
companion object {
var curSongDuration = 0L
private set
}
override fun onCreate() {
super.onCreate()
serviceScope.launch {
firebaseMusicSource.fetchMediaData()
}
val activityIntent = packageManager?.getLaunchIntentForPackage(packageName)?.let {
PendingIntent.getActivity(this, 0, it, 0)
}
mediaSession = MediaSessionCompat(this, SERVICE_TAG).apply {
setSessionActivity(activityIntent)
isActive = true
}
sessionToken = mediaSession.sessionToken
musicNotificationManager = MusicNotificationManager(
this,
mediaSession.sessionToken,
MusicPlayerNotificationListener(this)
) {
curSongDuration = exoPlayer.duration
}
val musicPlaybackPreparer = MusicPlaybackPreparer(firebaseMusicSource) {
curPlayingSong = it
preparePlayer(
firebaseMusicSource.songs,
it,
true
)
}
mediaSessionConnector = MediaSessionConnector(mediaSession)
mediaSessionConnector.setPlaybackPreparer(musicPlaybackPreparer)
mediaSessionConnector.setQueueNavigator(MusicQueueNavigator())
mediaSessionConnector.setPlayer(exoPlayer)
musicPlayerEventListener = MusicPlayerEventListener(this)
exoPlayer.addListener(musicPlayerEventListener)
musicNotificationManager.showNotification(exoPlayer)
}
private inner class MusicQueueNavigator : TimelineQueueNavigator(mediaSession) {
override fun getMediaDescription(player: Player, windowIndex: Int): MediaDescriptionCompat {
return firebaseMusicSource.songs[windowIndex].description
}
}
private fun preparePlayer(
songs: List<MediaMetadataCompat>,
itemToPlay: MediaMetadataCompat?,
playNow: Boolean
) {
val curSongIndex = if (curPlayingSong == null) 0 else songs.indexOf(itemToPlay)
exoPlayer.setMediaSource(firebaseMusicSource.asMediaSource(dataSourceFactory))
exoPlayer.prepare()
exoPlayer.seekTo(curSongIndex, 0L)
exoPlayer.playWhenReady = playNow
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
exoPlayer.stop()
}
override fun onDestroy() {
super.onDestroy()
serviceScope.cancel()
exoPlayer.removeListener(musicPlayerEventListener)
exoPlayer.release()
}
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): BrowserRoot? {
return BrowserRoot(MEDIA_ROOT_ID, null)
}
override fun onLoadChildren(
parentId: String,
result: Result<MutableList<MediaBrowserCompat.MediaItem>>
) {
when (parentId) {
MEDIA_ROOT_ID -> {
val resultsSent = firebaseMusicSource.whenReady { isInitialized ->
if (isPlayerInitialized) {
result.sendResult(firebaseMusicSource.asMediaItems())
if (!isInitialized && firebaseMusicSource.songs.isNotEmpty()) {
preparePlayer(
firebaseMusicSource.songs,
firebaseMusicSource.songs[0],
false
)
isPlayerInitialized = true
}
} else {
mediaSession.sendSessionEvent(NETWORK_ERROR, null)
result.sendResult(null)
}
}
if (!resultsSent) {
result.detach()
}
}
}
}
}
低于我的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.spotifyclone">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name=".SpotifyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SpotifyClone"
tools:targetApi="31">
<service android:name="com.example.spotifyclone.exoplayer.MusicService"
android:exported="false">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<activity
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
低于MusicNotificationManager.kt
@SuppressLint("Range")
class MusicNotificationManager(
private val context:Context,
sessionToken:MediaSessionCompat.Token,
notificationListener:PlayerNotificationManager.NotificationListener,
private val newSongCallback:() -> Unit
) {
private val notificationManager: PlayerNotificationManager
init {
val mediaController = MediaControllerCompat(context, sessionToken)
notificationManager = PlayerNotificationManager.Builder(
context,
NOTIFICATION_ID, NOTIFICATION_CHANNEL_ID
)
.setChannelNameResourceId(R.string.notification_channel_name)
.setChannelDescriptionResourceId(R.string.notification_channel_description)
.setMediaDescriptionAdapter(DescriptionAdapter(mediaController))
.setNotificationListener(notificationListener)
.setSmallIconResourceId(R.drawable.ic_music)
.build()
}
fun showNotification(player: Player) {
notificationManager.setPlayer(player)
}
private inner class DescriptionAdapter(
private val mediaController: MediaControllerCompat
) : PlayerNotificationManager.MediaDescriptionAdapter {
override fun getCurrentContentTitle(player: Player): CharSequence {
return mediaController.metadata.description.title.toString()
}
override fun createCurrentContentIntent(player: Player): PendingIntent? {
return mediaController.sessionActivity
}
override fun getCurrentContentText(player: Player): CharSequence? {
return mediaController.metadata.description.subtitle.toString()
}
override fun getCurrentLargeIcon(
player: Player,
callback: PlayerNotificationManager.BitmapCallback
): Bitmap? {
Glide.with(context).asBitmap()
.load(mediaController.metadata.description.iconUri)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
callback.onBitmap(resource)
}
override fun onLoadCleared(placeholder: Drawable?) = Unit
})
return null
}
}
}
我所做的,重建,失效,缓存和重新启动,并遵循所有的堆栈溢出的答案,我想知道我到底在哪里犯了错误,我必须做的是避免在我的应用程序崩溃。
发布于 2022-08-13 01:18:26
堆栈跟踪在源代码中提到了PlayerNotificationManager
第353行:
at com.google.android.exoplayer2.ui.PlayerNotificationManager$Builder.<init>(PlayerNotificationManager.java:353)
这正是这一行(您可以在github上找到源代码):
checkArgument(notificationId > 0);
如您所见,库将检查所传递的NOTIFICATION_ID
是否大于0。解决方案是将NOTIFICATION_ID
的定义更改为大于0的整数。祝你好运
https://stackoverflow.com/questions/73337662
复制相似问题