Audio -Vordergrundservice wird auf App Kill gestoppt oder getrennt, wenn dies nicht der Fall sein sollteAndroid

Forum für diejenigen, die für Android programmieren
Anonymous
 Audio -Vordergrundservice wird auf App Kill gestoppt oder getrennt, wenn dies nicht der Fall sein sollte

Post by Anonymous »

Ich baue einen Flutter -Android -Audio -Streaming -Service mit Exoplayer in Kotlin. Der Service spielt Live -Audio -Streams und zeigt Medienkontrollen über eine Benachrichtigung. Es funktioniert gut, während sich die App im Vordergrund oder im Hintergrund befindet. Wenn die App jedoch aus den jüngsten Apps oder getötet wird, stoppt der Dienst auch und die Benachrichtigung verschwindet-obwohl ich erwartet hatte, dass er bestehen bleibt.






























< /code>
Hauptaktivität < /p>
package com.example.simple_radio

import android.content.Intent
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.EventChannel

class MainActivity : FlutterActivity() {
private val CHANNEL = "audio.channel"
private val EVENT_CHANNEL = "audio.events"

companion object {
var eventSink: EventChannel.EventSink? = null
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
when (call.method) {
"play" -> {
val url = call.argument("url") ?: ""
val title = call.argument("title") ?: "Live Stream"
val image = call.argument("image") ?: "Live Stream"
val intent = Intent(this, AudioPlayerService::class.java).apply {
action = "ACTION_PLAY" // IMPORTANT: Use intent.action, not putExtra("action", ...)
putExtra("url", url)
putExtra("title", title)
putExtra("image", image)
}
startForegroundService(intent)
result.success(null)
}
"pause" -> {
val intent = Intent(this, AudioPlayerService::class.java).apply {
action = "ACTION_PAUSE"
}
startService(intent)
result.success(null)
}
"stop" -> {
val intent = Intent(this, AudioPlayerService::class.java).apply {
action = "ACTION_STOP"
}
startService(intent)
result.success(null)
}
"getStatus" -> {
val intent = Intent(this, AudioPlayerService::class.java).apply {
action = "GET_STATUS"
}
startService(intent)
result.success(null)
}
else -> result.notImplemented()
}
}
EventChannel(flutterEngine.dartExecutor.binaryMessenger, EVENT_CHANNEL).setStreamHandler(
object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}

override fun onCancel(arguments: Any?) {
eventSink = null
}
}
)
}
}
< /code>
audioplayerService < /p>
package com.example.simple_radio

import android.app.*
import android.content.Context
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem

class AudioPlayerService : Service() {
private lateinit var exoPlayer: ExoPlayer
private val NOTIF_ID = 1
private val CHANNEL_ID = "AudioPlayerChannel"
private var currentTitle: String = "Live Stream"
private var currentUrl: String = ""
private var currentImage: String = "https://demofree.sirv.com/nope-not-here.jpg"

override fun onCreate() {
super.onCreate()

val channel = NotificationChannel(
CHANNEL_ID,
"Audio Playback",
NotificationManager.IMPORTANCE_LOW
)
val manager = getSystemService(NotificationManager::class.java)
manager.createNotificationChannel(channel)

exoPlayer = ExoPlayer.Builder(this).build()
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val action = intent?.action
when (action) {
"ACTION_PLAY" -> {
currentUrl = intent.getStringExtra("url") ?: currentUrl
currentTitle = intent.getStringExtra("title") ?: currentTitle
currentImage = intent.getStringExtra("image") ?: currentImage
startForeground(NOTIF_ID, createNotification(currentTitle, true))
playAudio(currentUrl)
}
"ACTION_PAUSE" -> {
exoPlayer.pause()
sendEvent("paused")
updateNotification(false)
}
"ACTION_STOP" -> {
stopAudio()
}
"GET_STATUS" -> {
val status = if (::exoPlayer.isInitialized) {
when {
exoPlayer.isPlaying -> "playing"
exoPlayer.playWhenReady && exoPlayer.playbackState == ExoPlayer.STATE_READY -> "playing"
!exoPlayer.playWhenReady && exoPlayer.playbackState == ExoPlayer.STATE_READY -> "paused"
else -> "stopped"
}
} else {
"stopped"
}
sendEvent(status)
}
else -> {
stopSelf()
}
}
return START_STICKY
}

private fun playAudio(url: String) {
val mediaItem = MediaItem.fromUri(url)
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()
sendEvent("playing")
}

private fun stopAudio() {
if (::exoPlayer.isInitialized) {
exoPlayer.stop()
exoPlayer.release()
stopSelf()
sendEvent("stopped")
}
}

private fun sendEvent(status: String) {
MainActivity.eventSink?.success(mapOf(
"status" to status,
"title" to currentTitle,
"url" to currentUrl,
"image" to currentImage
))
}

private fun updateNotification(isPlaying: Boolean) {
val notification = createNotification(currentTitle, isPlaying)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(NOTIF_ID, notification)
}

private fun createNotification(title: String, isPlaying: Boolean): Notification {
// Intent to open the main activity
val openAppIntent = Intent(this, MainActivity::class.java).apply {
// Set flags based on app state
flags = if (MyApplicationLifeCycle.isAppInForeground) {
Intent.FLAG_ACTIVITY_SINGLE_TOP // Bring to front if already running
} else {
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK // Start new instance if not running
}
}

val openAppPendingIntent = PendingIntent.getActivity(
this, 0, openAppIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

val playIntent = PendingIntent.getBroadcast(
this, 0, Intent(this, NotificationActionReceiver::class.java).setAction("ACTION_PLAY"),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val pauseIntent = PendingIntent.getBroadcast(
this, 1, Intent(this, NotificationActionReceiver::class.java).setAction("ACTION_PAUSE"),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
val stopIntent = PendingIntent.getBroadcast(
this, 2, Intent(this, NotificationActionReceiver::class.java).setAction("ACTION_STOP"),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Now Playing \"$title\"")
.setSmallIcon(R.drawable.ic_notification)
.setColor(0xFF5722.toInt())
.setOngoing(true)
.setContentIntent(openAppPendingIntent)
.addAction(
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play,
if (isPlaying) "Pause" else "Play",
if (isPlaying) pauseIntent else playIntent
)
.addAction(R.drawable.ic_stop, "Stop", stopIntent)
.build()
}

override fun onDestroy() {
super.onDestroy()
}

override fun onBind(intent: Intent?): IBinder? = null
}

< /code>
NotificationReciever < /p>
package com.example.simple_radio

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build

class NotificationActionReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action ?: return
val serviceIntent = Intent(context, AudioPlayerService::class.java).apply {
this.action = action
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startService(serviceIntent)
context.startForegroundService(serviceIntent)
} else {
context.startService(serviceIntent)
}
}
}
< /code>
Während die App geöffnet ist, ist die Verwendung der Methode und des Ereigniskanals, um Ereignisse anzuhören und die Benutzeroberfläche basierend darauf zu aktualisieren. Wenn ich einen Stream starte, übergende ich Daten an audioplayerService und das Audio startet. Das Problem ist, dass der Vordergrunddienst beim Töten von App ebenfalls getötet wird. Es ist auch fehlerhaft, da es manchmal nicht neu startet. Im Moment höre ich den App -Lebenszyklus an und starte den Player in der App, die abgetrennt wird. Dies garantiert, dass das Radio neu gestartet wird, aber die Verzögerung ist immer noch da.>

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post