Move MusicRepository initialization to coroutine

Move the init call to MusicRepostiory to a coroutine so that it doesnt stop the UI thread.
This commit is contained in:
OxygenCobalt 2020-08-18 15:33:59 -06:00
parent 21a110edb0
commit 3134e313a3
3 changed files with 55 additions and 17 deletions

View file

@ -10,14 +10,18 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
import org.oxycblt.auxio.music.MusicRepository
class LibraryFragment : Fragment() {
// Lazily initiate the ViewModel when its first referenced.
// Not because this does anything, it just looks nicer.
private val libraryModel: LibraryViewModel by lazy {
ViewModelProvider(this).get(LibraryViewModel::class.java)
ViewModelProvider(
this,
LibraryViewModel.Factory(
requireActivity().application
)
).get(LibraryViewModel::class.java)
}
override fun onCreateView(
@ -29,7 +33,7 @@ class LibraryFragment : Fragment() {
inflater, R.layout.fragment_library, container, false
)
MusicRepository.getInstance().init(requireActivity().application)
libraryModel
Log.d(this::class.simpleName, "Fragment created.")

View file

@ -1,13 +1,42 @@
package org.oxycblt.auxio.library
import android.app.Application
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.oxycblt.auxio.music.MusicRepository
class LibraryViewModel() : ViewModel() {
class LibraryViewModel(private val app: Application) : ViewModel() {
// TODO: Implement music data in ViewModel
private val viewModelJob = Job()
private val ioScope = CoroutineScope(
Dispatchers.IO
)
init {
startMusicRepo()
Log.d(this::class.simpleName, "ViewModel created.")
}
// TODO: Temp function, remove when LoadingFragment is added
private fun startMusicRepo() {
ioScope.launch {
MusicRepository.getInstance().init(app)
}
}
class Factory(private val application: Application) : ViewModelProvider.Factory {
@Suppress("unchecked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LibraryViewModel::class.java)) {
return LibraryViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
}

View file

@ -4,7 +4,6 @@ import android.app.Application
import android.content.ContentResolver
import android.content.ContentUris
import android.database.Cursor
import android.graphics.Bitmap
import android.media.MediaMetadataRetriever
import android.provider.MediaStore
import android.provider.MediaStore.Audio.AudioColumns
@ -47,13 +46,15 @@ class MusicRepository {
app.contentResolver
)
Log.i(this::class.simpleName, "Starting music search...")
// Index music files from shared storage
musicCursor?.use { cursor ->
val idIndex = cursor.getColumnIndexOrThrow(AudioColumns._ID)
val displayIndex = cursor.getColumnIndexOrThrow(AudioColumns.DISPLAY_NAME)
var retriever = MediaMetadataRetriever()
val retriever = MediaMetadataRetriever()
while (cursor.moveToNext()) {
val id = cursor.getLong(idIndex)
@ -84,17 +85,22 @@ class MusicRepository {
MediaMetadataRetriever.METADATA_KEY_GENRE
)
val year = (retriever.extractMetadata(
val year = (
retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_YEAR
) ?: "0").toInt()
) ?: "0"
).toInt()
// Track is formatted as X/0, so trim off the /0 part to parse
// the track number correctly.
val track = (retriever.extractMetadata(
val track = (
retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER
) ?: "0/0").split("/")[0].toInt()
) ?: "0/0"
).split("/")[0].toInt()
// Something has gone horribly wrong if a file has no duration.
// Something has gone horribly wrong if a file has no duration,
// so assert it as such.
val duration = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_DURATION
)!!.toLong()
@ -117,7 +123,7 @@ class MusicRepository {
)
}
// Close the retriever when done so that it gets garbage collected
// Close the retriever when done so that it gets garbage collected [I hope]
retriever.close()
}
@ -127,7 +133,6 @@ class MusicRepository {
)
return songList
} catch (error: Exception) {
// TODO: Add better error handling