I have a bound service that is started as foreground service for handling exoplayer.
Here is how my fragment handles the service -
@AndroidEntryPoint
class AudioPlayerFragment: Fragment() {
private var binding: AudioPlayerFragmentBinding by autoCleared()
private lateinit var podcast: Podcast
private lateinit var podcastPlayerService: PodcastPlayerService
private var isBound = false
private val connection = object: ServiceConnection {
override fun onServiceConnected(p0: ComponentName?, iBinder: IBinder?) {
val binder = iBinder as PodcastPlayerService.LocalBinder
podcastPlayerService = binder.getService()
isBound = true
initPlayer()
}
override fun onServiceDisconnected(p0: ComponentName?) {
isBound = false
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = AudioPlayerFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
podcast = arguments?.getParcelable(ExtrasKeyAndValues.KEY_PODCAST)!!
binding.title.text = podcast.title
binding.description.text = podcast.description
startPodcastPlayerService(podcast)
binding.exoPlayerView.useController = true
binding.exoPlayerView.showController()
binding.exoPlayerView.controllerAutoShow = true
binding.exoPlayerView.controllerHideOnTouch = false
}
override fun onStart() {
super.onStart()
Intent(activity, PodcastPlayerService::class.java).also {
intent -> activity?.bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
initPlayer()
}
override fun onStop() {
activity?.unbindService(connection)
isBound = false
super.onStop()
}
private fun initPlayer() {
if (isBound) {
val player: SimpleExoPlayer = podcastPlayerService.getPlayerInstance()
binding.exoPlayerView.player = player
}
}
private fun startPodcastPlayerService(podcast: Podcast) {
val intent = Intent(context, PodcastPlayerService::class.java)
val serviceBundle = Bundle()
serviceBundle.putParcelable(ExtrasKeyAndValues.KEY_PODCAST, podcast)
intent.putExtra(ExtrasKeyAndValues.BUNDLE_PODCAST_SERVICE, serviceBundle)
context?.let { Util.startForegroundService(it, intent) }
}
}
The problem is that the service (obviously) restarts when the phone is rotated (config change). How do I architect my app in a way that the service is not restarted but just attaches itself to the fragment and its UI?
Placing it in a ViewModel
does not make sense because it is recommended to avoid putting android framework related stuff in there.
The best thing here to create something like VideoHelper
class that will include all player related code and initialization. Includes the function that will control the state of the player and other related things. Referring to your question service is not restarted but just attaches itself to the fragment and its UI
as I remember I implemented the logic that saved the state and progress of the video in onPause
or onStop
and set it back when onResume
. Basically, you need to create in separate VideoHelper
functions like getProgress
and call it in onPause
or onStop
and function setProgress
that you should call from onResume
and before setting it check if it not empty or null. The progress you can save any way you want - shared preferences or some static data or anything else.