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 questionservice 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 inonPause
oronStop
and set it back whenonResume
. Basically, you need to create in separateVideoHelper
functions likegetProgress
and call it inonPause
oronStop
and functionsetProgress
that you should call fromonResume
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.