Tidied up usage of GlobalScope to the profit of AndroidX's lifecycle coroutine scopes.

This commit is contained in:
Antoine POPINEAU 2020-06-25 01:26:15 +02:00
parent eb57b4c872
commit 9c61fcf462
No known key found for this signature in database
GPG Key ID: A78AC64694F84063
25 changed files with 117 additions and 151 deletions

View File

@ -103,6 +103,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.1.0")
implementation("androidx.core:core-ktx:1.5.0-alpha01")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha05")
implementation("androidx.coordinatorlayout:coordinatorlayout:1.1.0")
implementation("androidx.preference:preference:1.1.1")
implementation("androidx.recyclerview:recyclerview:1.1.0")

View File

@ -17,10 +17,6 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<!-- <meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.android.exoplayer2.ext.cast.DefaultCastOptionsProvider"/> -->
<activity
android:name="com.github.apognu.otter.activities.SplashActivity"
android:launchMode="singleInstance"

View File

@ -1,19 +1,21 @@
package com.github.apognu.otter.activities
import android.os.Bundle
import kotlinx.coroutines.flow.collect
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.Otter
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.DownloadsAdapter
import com.github.apognu.otter.utils.*
import com.github.apognu.otter.utils.Event
import com.github.apognu.otter.utils.EventBus
import com.github.apognu.otter.utils.getMetadata
import com.google.android.exoplayer2.offline.Download
import kotlinx.android.synthetic.main.activity_downloads.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -34,7 +36,7 @@ class DownloadsActivity : AppCompatActivity() {
downloads.adapter = it
}
GlobalScope.launch(IO) {
lifecycleScope.launch(Default) {
while (true) {
delay(1000)
refreshProgress()
@ -45,7 +47,7 @@ class DownloadsActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
GlobalScope.launch(IO) {
lifecycleScope.launch(Default) {
EventBus.get().collect { event ->
if (event is Event.DownloadChanged) {
refreshTrack(event.download)
@ -57,7 +59,7 @@ class DownloadsActivity : AppCompatActivity() {
}
private fun refresh() {
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
val cursor = Otter.get().exoDownloadManager.downloadIndex.getDownloads()
adapter.downloads.clear()

View File

@ -5,6 +5,7 @@ import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.github.apognu.otter.R
import com.github.apognu.otter.fragments.LoginDialog
import com.github.apognu.otter.utils.AppContext
@ -17,7 +18,6 @@ import com.google.gson.Gson
import com.preference.PowerPreference
import kotlinx.android.synthetic.main.activity_login.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
data class FwCredentials(val token: String, val non_field_errors: List<String>?)
@ -89,7 +89,7 @@ class LoginActivity : AppCompatActivity() {
show(supportFragmentManager, "LoginDialog")
}
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
try {
val (_, response, result) = Fuel.post("$hostname/api/v1/token/", body)
.awaitObjectResponseResult(gsonDeserializerOf(FwCredentials::class.java))
@ -146,7 +146,7 @@ class LoginActivity : AppCompatActivity() {
show(supportFragmentManager, "LoginDialog")
}
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
try {
val (_, _, result) = Fuel.get("$hostname/api/v1/tracks/")
.awaitObjectResponseResult(gsonDeserializerOf(FwCredentials::class.java))

View File

@ -5,7 +5,6 @@ import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Bitmap
import android.os.Bundle
import android.util.DisplayMetrics
@ -19,6 +18,7 @@ import androidx.core.graphics.drawable.toDrawable
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import com.github.apognu.otter.R
import com.github.apognu.otter.fragments.*
import com.github.apognu.otter.playback.MediaControlsManager
@ -38,11 +38,9 @@ import com.squareup.picasso.Picasso
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.partial_now_playing.*
import kotlinx.android.synthetic.main.row_download.*
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -55,10 +53,6 @@ class MainActivity : AppCompatActivity() {
private val favoriteRepository = FavoritesRepository(this)
private val favoriteCheckRepository = FavoritedRepository(this)
private var eventBus: Job? = null
private var commandBus: Job? = null
private var progressBus: Job? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -76,22 +70,18 @@ class MainActivity : AppCompatActivity() {
.replace(R.id.container, BrowseFragment())
.commit()
CommandBus.send(Command.RefreshService)
watchEventBus()
}
override fun onResume() {
super.onResume()
if (eventBus == null) {
watchEventBus()
}
CommandBus.send(Command.RefreshService)
startService(Intent(this, PlayerService::class.java))
DownloadService.start(this, PinService::class.java)
GlobalScope.launch(IO) {
CommandBus.send(Command.RefreshService)
lifecycleScope.launch(IO) {
Userinfo.get()
}
@ -132,19 +122,6 @@ class MainActivity : AppCompatActivity() {
}
}
override fun onPause() {
super.onPause()
eventBus?.cancel()
eventBus = null
commandBus?.cancel()
commandBus = null
progressBus?.cancel()
progressBus = null
}
override fun onBackPressed() {
if (now_playing.isOpened()) {
now_playing.close()
@ -157,8 +134,6 @@ class MainActivity : AppCompatActivity() {
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.toolbar, menu)
// CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.cast)
menu?.findItem(R.id.nav_only_my_music)?.isChecked = Settings.getScope() == "me"
return true
@ -210,10 +185,6 @@ class MainActivity : AppCompatActivity() {
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
}
private fun launchFragment(fragment: Fragment) {
supportFragmentManager.fragments.lastOrNull()?.also { oldFragment ->
oldFragment.enterTransition = null
@ -237,7 +208,7 @@ class MainActivity : AppCompatActivity() {
@SuppressLint("NewApi")
private fun watchEventBus() {
eventBus = GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.LogOut -> {
@ -312,7 +283,7 @@ class MainActivity : AppCompatActivity() {
}
}
commandBus = GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refreshCurrentTrack(command.track)
@ -320,7 +291,7 @@ class MainActivity : AppCompatActivity() {
}
}
progressBus = GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
ProgressBus.get().collect { (current, duration, percent) ->
now_playing_progress.progress = percent
now_playing_details_progress.progress = percent
@ -384,7 +355,7 @@ class MainActivity : AppCompatActivity() {
}
if (now_playing_details_cover == null) {
GlobalScope.launch(IO) {
lifecycleScope.launch(Default) {
val width = DisplayMetrics().apply {
windowManager.defaultDisplay.getMetrics(this)
}.widthPixels
@ -437,8 +408,8 @@ class MainActivity : AppCompatActivity() {
}
now_playing_details_favorite?.let { now_playing_details_favorite ->
favoriteCheckRepository.fetch().untilNetwork(IO) { favorites, _, _ ->
GlobalScope.launch(Main) {
favoriteCheckRepository.fetch().untilNetwork(lifecycleScope, IO) { favorites, _, _ ->
lifecycleScope.launch(Main) {
track.favorite = favorites.contains(track.id)
when (track.favorite) {
@ -507,7 +478,7 @@ class MainActivity : AppCompatActivity() {
private fun incrementListenCount(track: Track?) {
track?.let {
GlobalScope.launch(IO) {
lifecycleScope.launch(IO) {
try {
Fuel
.post(mustNormalizeUrl("/api/v1/history/listenings/"))

View File

@ -3,6 +3,7 @@ package com.github.apognu.otter.activities
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.SearchAdapter
@ -66,21 +67,21 @@ class SearchActivity : AppCompatActivity() {
adapter.tracks.clear()
adapter.notifyDataSetChanged()
artistsRepository.fetch(Repository.Origin.Network.origin).untilNetwork { artists, _, _ ->
artistsRepository.fetch(Repository.Origin.Network.origin).untilNetwork(lifecycleScope) { artists, _, _ ->
done++
adapter.artists.addAll(artists)
refresh()
}
albumsRepository.fetch(Repository.Origin.Network.origin).untilNetwork { albums, _, _ ->
albumsRepository.fetch(Repository.Origin.Network.origin).untilNetwork(lifecycleScope) { albums, _, _ ->
done++
adapter.albums.addAll(albums)
refresh()
}
tracksRepository.fetch(Repository.Origin.Network.origin).untilNetwork { tracks, _, _ ->
tracksRepository.fetch(Repository.Origin.Network.origin).untilNetwork(lifecycleScope) { tracks, _, _ ->
done++
adapter.tracks.addAll(tracks)

View File

@ -7,17 +7,20 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.R
import com.github.apognu.otter.fragments.FunkwhaleAdapter
import com.github.apognu.otter.utils.*
import com.github.apognu.otter.utils.AppContext
import com.github.apognu.otter.utils.Event
import com.github.apognu.otter.utils.EventBus
import com.github.apognu.otter.utils.Radio
import com.github.apognu.otter.views.LoadingImageView
import com.preference.PowerPreference
import kotlinx.android.synthetic.main.row_radio.view.*
import kotlinx.android.synthetic.main.row_radio_header.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class RadiosAdapter(val context: Context?, private val listener: OnRadioClickListener) : FunkwhaleAdapter<Radio, RadiosAdapter.ViewHolder>() {
class RadiosAdapter(val context: Context?, val scope: CoroutineScope, private val listener: OnRadioClickListener) : FunkwhaleAdapter<Radio, RadiosAdapter.ViewHolder>() {
interface OnRadioClickListener {
fun onClick(holder: ViewHolder, radio: Radio)
}
@ -139,7 +142,7 @@ class RadiosAdapter(val context: Context?, private val listener: OnRadioClickLis
art.setColorFilter(context.getColor(R.color.controlForeground))
GlobalScope.launch(Main) {
scope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.RadioStarted -> {

View File

@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import androidx.transition.Fade
@ -24,7 +25,6 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.fragment_albums.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
@ -126,7 +126,7 @@ class AlbumsFragment : FunkwhaleFragment<Album, AlbumsAdapter>() {
play.icon = loader
play.isClickable = false
GlobalScope.launch(IO) {
lifecycleScope.launch(IO) {
artistTracksRepository.fetch(Repository.Origin.Network.origin)
.map { it.data }
.toList()

View File

@ -1,6 +1,7 @@
package com.github.apognu.otter.fragments
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.FavoritesAdapter
@ -11,7 +12,6 @@ import com.google.android.exoplayer2.offline.Download
import kotlinx.android.synthetic.main.fragment_favorites.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -32,7 +32,7 @@ class FavoritesFragment : FunkwhaleFragment<Track, FavoritesAdapter>() {
override fun onResume() {
super.onResume()
GlobalScope.launch(IO) {
lifecycleScope.launch(IO) {
RequestBus.send(Request.GetCurrentTrack).wait<Response.CurrentTrack>()?.let { response ->
withContext(Main) {
adapter.currentTrack = response.track
@ -49,7 +49,7 @@ class FavoritesFragment : FunkwhaleFragment<Track, FavoritesAdapter>() {
}
private fun watchEventBus() {
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.DownloadChanged -> refreshDownloadedTrack(message.download)
@ -57,7 +57,7 @@ class FavoritesFragment : FunkwhaleFragment<Track, FavoritesAdapter>() {
}
}
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refreshCurrentTrack(command.track)

View File

@ -5,16 +5,19 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.repositories.HttpUpstream
import com.github.apognu.otter.repositories.Repository
import com.github.apognu.otter.utils.*
import com.github.apognu.otter.utils.Cache
import com.github.apognu.otter.utils.Event
import com.github.apognu.otter.utils.EventBus
import com.github.apognu.otter.utils.untilNetwork
import com.google.gson.Gson
import kotlinx.android.synthetic.main.fragment_artists.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -70,7 +73,7 @@ abstract class FunkwhaleFragment<D : Any, A : FunkwhaleAdapter<D, *>> : Fragment
}
if (listener == null) {
listener = GlobalScope.launch(IO) {
listener = lifecycleScope.launch(IO) {
EventBus.get().collect { event ->
if (event is Event.ListingsChanged) {
withContext(Main) {
@ -92,8 +95,8 @@ abstract class FunkwhaleFragment<D : Any, A : FunkwhaleAdapter<D, *>> : Fragment
swiper?.isRefreshing = true
}
repository.fetch(upstreams, size).untilNetwork(IO) { data, isCache, hasMore ->
GlobalScope.launch(Main) {
repository.fetch(upstreams, size).untilNetwork(lifecycleScope, IO) { data, isCache, hasMore ->
lifecycleScope.launch(Main) {
if (isCache) {
adapter.data = data.toMutableList()
adapter.notifyDataSetChanged()
@ -112,7 +115,7 @@ abstract class FunkwhaleFragment<D : Any, A : FunkwhaleAdapter<D, *>> : Fragment
if (!hasMore) {
swiper?.isRefreshing = false
GlobalScope.launch(IO) {
withContext(IO) {
if (adapter.data.isNotEmpty()) {
try {
repository.cacheId?.let { cacheId ->

View File

@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.TracksAdapter
@ -12,7 +13,6 @@ import com.github.apognu.otter.utils.*
import kotlinx.android.synthetic.main.partial_queue.*
import kotlinx.android.synthetic.main.partial_queue.view.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -44,7 +44,7 @@ class LandscapeQueueFragment : Fragment() {
}
private fun refresh() {
GlobalScope.launch(Main) {
activity?.lifecycleScope?.launch(Main) {
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let { response ->
adapter?.let {
it.data = response.queue.toMutableList()
@ -63,7 +63,7 @@ class LandscapeQueueFragment : Fragment() {
}
private fun watchEventBus() {
GlobalScope.launch(Main) {
activity?.lifecycleScope?.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.QueueChanged -> refresh()
@ -71,7 +71,7 @@ class LandscapeQueueFragment : Fragment() {
}
}
GlobalScope.launch(Main) {
activity?.lifecycleScope?.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refresh()

View File

@ -5,6 +5,7 @@ import android.view.Gravity
import android.view.View
import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.PlaylistTracksAdapter
@ -15,7 +16,6 @@ import com.squareup.picasso.Picasso
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.fragment_tracks.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -73,7 +73,7 @@ class PlaylistTracksFragment : FunkwhaleFragment<PlaylistTrack, PlaylistTracksAd
override fun onResume() {
super.onResume()
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
RequestBus.send(Request.GetCurrentTrack).wait<Response.CurrentTrack>()?.let { response ->
adapter.currentTrack = response.track
adapter.notifyDataSetChanged()
@ -144,7 +144,7 @@ class PlaylistTracksFragment : FunkwhaleFragment<PlaylistTrack, PlaylistTracksAd
}
imageView?.let { view ->
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
Picasso.get()
.maybeLoad(maybeNormalizeUrl(url))
.fit()
@ -157,7 +157,7 @@ class PlaylistTracksFragment : FunkwhaleFragment<PlaylistTrack, PlaylistTracksAd
}
private fun watchEventBus() {
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refreshCurrentTrack(command.track)

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.TracksAdapter
@ -18,7 +19,6 @@ import kotlinx.android.synthetic.main.fragment_queue.view.*
import kotlinx.android.synthetic.main.partial_queue.*
import kotlinx.android.synthetic.main.partial_queue.view.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -66,7 +66,7 @@ class QueueFragment : BottomSheetDialogFragment() {
}
private fun refresh() {
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
RequestBus.send(Request.GetQueue).wait<Response.Queue>()?.let { response ->
included?.let { included ->
adapter?.let {
@ -87,7 +87,7 @@ class QueueFragment : BottomSheetDialogFragment() {
}
private fun watchEventBus() {
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.QueueChanged -> refresh()
@ -95,7 +95,7 @@ class QueueFragment : BottomSheetDialogFragment() {
}
}
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refresh()

View File

@ -2,6 +2,7 @@ package com.github.apognu.otter.fragments
import android.os.Bundle
import androidx.core.view.forEach
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.RadiosAdapter
@ -9,7 +10,6 @@ import com.github.apognu.otter.repositories.RadiosRepository
import com.github.apognu.otter.utils.*
import kotlinx.android.synthetic.main.fragment_radios.*
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
@ -20,7 +20,7 @@ class RadiosFragment : FunkwhaleFragment<Radio, RadiosAdapter>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = RadiosAdapter(context, RadioClickListener())
adapter = RadiosAdapter(context, lifecycleScope, RadioClickListener())
repository = RadiosRepository(context)
}
@ -34,11 +34,12 @@ class RadiosFragment : FunkwhaleFragment<Radio, RadiosAdapter>() {
CommandBus.send(Command.PlayRadio(radio))
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
EventBus.get().collect { message ->
when (message) {
is Event.RadioStarted ->
if (radios != null) { recycler.forEach {
if (radios != null) {
recycler.forEach {
it.isEnabled = true
it.isClickable = true
}

View File

@ -5,6 +5,7 @@ import android.view.Gravity
import android.view.View
import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.github.apognu.otter.R
import com.github.apognu.otter.adapters.TracksAdapter
@ -17,7 +18,6 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
import kotlinx.android.synthetic.main.fragment_tracks.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -81,13 +81,11 @@ class TracksFragment : FunkwhaleFragment<Track, TracksAdapter>() {
override fun onResume() {
super.onResume()
GlobalScope.launch(IO) {
lifecycleScope.launch(Main) {
RequestBus.send(Request.GetCurrentTrack).wait<Response.CurrentTrack>()?.let { response ->
withContext(Main) {
adapter.currentTrack = response.track
adapter.notifyDataSetChanged()
}
}
refreshDownloadedTracks()
}
@ -138,7 +136,7 @@ class TracksFragment : FunkwhaleFragment<Track, TracksAdapter>() {
}
private fun watchEventBus() {
GlobalScope.launch(IO) {
lifecycleScope.launch(IO) {
EventBus.get().collect { message ->
when (message) {
is Event.DownloadChanged -> refreshDownloadedTrack(message.download)
@ -146,7 +144,7 @@ class TracksFragment : FunkwhaleFragment<Track, TracksAdapter>() {
}
}
GlobalScope.launch(Main) {
lifecycleScope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshTrack -> refreshCurrentTrack(command.track)

View File

@ -16,11 +16,11 @@ import com.github.apognu.otter.R
import com.github.apognu.otter.activities.MainActivity
import com.github.apognu.otter.utils.*
import com.squareup.picasso.Picasso
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.launch
class MediaControlsManager(val context: Service, private val mediaSession: MediaSessionCompat) {
class MediaControlsManager(val context: Service, private val scope: CoroutineScope, private val mediaSession: MediaSessionCompat) {
companion object {
const val NOTIFICATION_ACTION_OPEN_QUEUE = 0
const val NOTIFICATION_ACTION_PREVIOUS = 1
@ -39,7 +39,7 @@ class MediaControlsManager(val context: Service, private val mediaSession: Media
false -> R.drawable.play
}
GlobalScope.launch(IO) {
scope.launch(Default) {
val openIntent = Intent(context, MainActivity::class.java).apply { action = NOTIFICATION_ACTION_OPEN_QUEUE.toString() }
val openPendingIntent = PendingIntent.getActivity(context, 0, openIntent, 0)

View File

@ -14,13 +14,16 @@ import com.google.android.exoplayer2.offline.DownloadService
import com.google.android.exoplayer2.scheduler.Scheduler
import com.google.android.exoplayer2.ui.DownloadNotificationHelper
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import java.util.*
class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) {
private val scope: CoroutineScope = CoroutineScope(Job() + Main)
companion object {
fun download(context: Context, track: Track) {
track.bestUpload()?.let { upload ->
@ -45,7 +48,7 @@ class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
buildResumeDownloadsIntent(this, PinService::class.java, true)
GlobalScope.launch(Main) {
scope.launch(Main) {
RequestBus.get().collect { request ->
when (request) {
is Request.GetDownloads -> request.channel?.offer(Response.Downloads(getDownloads()))

View File

@ -21,23 +21,24 @@ import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class PlayerService : Service() {
private lateinit var queue: QueueManager
private val jobs = mutableListOf<Job>()
private var started = false
private val scope: CoroutineScope = CoroutineScope(Job() + Main)
private lateinit var audioManager: AudioManager
private var audioFocusRequest: AudioFocusRequest? = null
private val audioFocusChangeListener = AudioFocusChange()
private var stateWhenLostFocus = false
private lateinit var queue: QueueManager
private lateinit var mediaControlsManager: MediaControlsManager
private lateinit var mediaSession: MediaSessionCompat
private lateinit var player: SimpleExoPlayer
@ -50,7 +51,9 @@ class PlayerService : Service() {
private lateinit var radioPlayer: RadioPlayer
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (jobs.isEmpty()) watchEventBus()
if (!started) watchEventBus()
started = true
return START_STICKY
}
@ -59,7 +62,7 @@ class PlayerService : Service() {
super.onCreate()
queue = QueueManager(this)
radioPlayer = RadioPlayer(this)
radioPlayer = RadioPlayer(this, scope)
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
@ -83,7 +86,7 @@ class PlayerService : Service() {
isActive = true
}
mediaControlsManager = MediaControlsManager(this, mediaSession)
mediaControlsManager = MediaControlsManager(this, scope, mediaSession)
player = SimpleExoPlayer.Builder(this).build().apply {
playWhenReady = false
@ -127,7 +130,7 @@ class PlayerService : Service() {
}
private fun watchEventBus() {
jobs.add(GlobalScope.launch(Main) {
scope.launch(Main) {
CommandBus.get().collect { command ->
when (command) {
is Command.RefreshService -> {
@ -193,9 +196,9 @@ class PlayerService : Service() {
mediaControlsManager.tick()
}
}
})
}
jobs.add(GlobalScope.launch(Main) {
scope.launch(Main) {
RequestBus.get().collect { request ->
when (request) {
is Request.GetCurrentTrack -> request.channel?.offer(Response.CurrentTrack(queue.current()))
@ -203,9 +206,9 @@ class PlayerService : Service() {
is Request.GetQueue -> request.channel?.offer(Response.Queue(queue.get()))
}
}
})
}
jobs.add(GlobalScope.launch(Main) {
scope.launch(Main) {
while (true) {
delay(1000)
@ -215,18 +218,13 @@ class PlayerService : Service() {
ProgressBus.send(current, duration, percent)
}
}
})
}
}
override fun onBind(intent: Intent?): IBinder? = null
@SuppressLint("NewApi")
override fun onDestroy() {
jobs.forEach {
it.cancel()
jobs.remove(it)
}
try {
unregisterReceiver(headphonesUnpluggedReceiver)
} catch (_: Exception) {
@ -372,7 +370,7 @@ class PlayerService : Service() {
mediaControlsManager.updateNotification(queue.current(), player.playWhenReady)
if (queue.get().isNotEmpty() && queue.current() == queue.get().last() && radioPlayer.isActive()) {
GlobalScope.launch(IO) {
scope.launch(IO) {
if (radioPlayer.lock.tryAcquire()) {
radioPlayer.prepareNextTrack()
radioPlayer.lock.release()

View File

@ -10,9 +10,9 @@ import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
import com.github.kittinunf.fuel.coroutines.awaitObjectResult
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
@ -25,7 +25,7 @@ data class RadioTrackBody(val session: Int)
data class RadioTrack(val position: Int, val track: RadioTrackID)
data class RadioTrackID(val id: Int)
class RadioPlayer(val context: Context) {
class RadioPlayer(val context: Context, val scope: CoroutineScope) {
val lock = Semaphore(1)
private var currentRadio: Radio? = null
@ -52,7 +52,7 @@ class RadioPlayer(val context: Context) {
currentRadio = radio
session = null
GlobalScope.launch(IO) {
scope.launch(IO) {
createSession()
}
}

View File

@ -9,7 +9,6 @@ import com.github.kittinunf.fuel.gson.gsonDeserializerOf
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.io.BufferedReader
@ -47,7 +46,7 @@ class FavoritesRepository(override val context: Context?) : Repository<Track, Tr
}
}
GlobalScope.launch(IO) {
scope.launch(IO) {
request
.header("Content-Type", "application/json")
.body(Gson().toJson(body))
@ -64,7 +63,7 @@ class FavoritesRepository(override val context: Context?) : Repository<Track, Tr
}
}
GlobalScope.launch(IO) {
scope.launch(IO) {
request
.header("Content-Type", "application/json")
.body(Gson().toJson(body))

View File

@ -3,7 +3,9 @@ package com.github.apognu.otter.repositories
import android.content.Context
import com.github.apognu.otter.utils.Cache
import com.github.apognu.otter.utils.CacheItem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.*
import java.io.BufferedReader
@ -12,6 +14,8 @@ interface Upstream<D> {
}
abstract class Repository<D : Any, C : CacheItem<D>> {
protected val scope: CoroutineScope = CoroutineScope(Job() + IO)
enum class Origin(val origin: Int) {
Cache(0b01),
Network(0b10)

View File

@ -77,7 +77,7 @@ object EventBus {
object CommandBus {
fun send(command: Command) {
GlobalScope.launch {
GlobalScope.launch(IO) {
Otter.get().commandBus.offer(command)
}
}
@ -101,7 +101,7 @@ object RequestBus {
object ProgressBus {
fun send(current: Int, duration: Int, percent: Int) {
GlobalScope.launch {
GlobalScope.launch(IO) {
Otter.get().progressBus.send(Triple(current, duration, percent))
}
}

View File

@ -10,15 +10,15 @@ import com.google.android.exoplayer2.offline.Download
import com.google.gson.Gson
import com.squareup.picasso.Picasso
import com.squareup.picasso.RequestCreator
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlin.coroutines.CoroutineContext
inline fun <D> Flow<Repository.Response<D>>.untilNetwork(context: CoroutineContext = Main, crossinline callback: (data: List<D>, isCache: Boolean, hasMore: Boolean) -> Unit) {
GlobalScope.launch(context) {
inline fun <D> Flow<Repository.Response<D>>.untilNetwork(scope: CoroutineScope, context: CoroutineContext = Main, crossinline callback: (data: List<D>, isCache: Boolean, hasMore: Boolean) -> Unit) {
scope.launch(context) {
collect { data ->
callback(data.data, data.origin == Repository.Origin.Cache, data.hasMore)
}

View File

@ -2,13 +2,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- <item
android:id="@+id/cast"
android:iconTint="@android:color/white"
android:title="@string/toolbar_cast"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="ifRoom" /> -->
<item
android:id="@+id/nav_search"
android:icon="@drawable/search"

View File

@ -8,13 +8,6 @@
android:title="@string/playback_queue"
app:showAsAction="ifRoom" />
<!-- <item
android:id="@+id/cast"
android:iconTint="@android:color/white"
android:title="@string/toolbar_cast"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="ifRoom" /> -->
<item
android:id="@+id/nav_search"
android:icon="@drawable/search"