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:
parent
21a110edb0
commit
3134e313a3
3 changed files with 55 additions and 17 deletions
|
@ -10,14 +10,18 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
|
import org.oxycblt.auxio.databinding.FragmentLibraryBinding
|
||||||
import org.oxycblt.auxio.music.MusicRepository
|
|
||||||
|
|
||||||
class LibraryFragment : Fragment() {
|
class LibraryFragment : Fragment() {
|
||||||
|
|
||||||
// Lazily initiate the ViewModel when its first referenced.
|
// Lazily initiate the ViewModel when its first referenced.
|
||||||
// Not because this does anything, it just looks nicer.
|
// Not because this does anything, it just looks nicer.
|
||||||
private val libraryModel: LibraryViewModel by lazy {
|
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(
|
override fun onCreateView(
|
||||||
|
@ -29,7 +33,7 @@ class LibraryFragment : Fragment() {
|
||||||
inflater, R.layout.fragment_library, container, false
|
inflater, R.layout.fragment_library, container, false
|
||||||
)
|
)
|
||||||
|
|
||||||
MusicRepository.getInstance().init(requireActivity().application)
|
libraryModel
|
||||||
|
|
||||||
Log.d(this::class.simpleName, "Fragment created.")
|
Log.d(this::class.simpleName, "Fragment created.")
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,42 @@
|
||||||
package org.oxycblt.auxio.library
|
package org.oxycblt.auxio.library
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.lifecycle.ViewModel
|
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 {
|
init {
|
||||||
|
startMusicRepo()
|
||||||
|
|
||||||
Log.d(this::class.simpleName, "ViewModel created.")
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.app.Application
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.ContentUris
|
import android.content.ContentUris
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.media.MediaMetadataRetriever
|
import android.media.MediaMetadataRetriever
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
@ -47,13 +46,15 @@ class MusicRepository {
|
||||||
app.contentResolver
|
app.contentResolver
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Log.i(this::class.simpleName, "Starting music search...")
|
||||||
|
|
||||||
// Index music files from shared storage
|
// Index music files from shared storage
|
||||||
musicCursor?.use { cursor ->
|
musicCursor?.use { cursor ->
|
||||||
|
|
||||||
val idIndex = cursor.getColumnIndexOrThrow(AudioColumns._ID)
|
val idIndex = cursor.getColumnIndexOrThrow(AudioColumns._ID)
|
||||||
val displayIndex = cursor.getColumnIndexOrThrow(AudioColumns.DISPLAY_NAME)
|
val displayIndex = cursor.getColumnIndexOrThrow(AudioColumns.DISPLAY_NAME)
|
||||||
|
|
||||||
var retriever = MediaMetadataRetriever()
|
val retriever = MediaMetadataRetriever()
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
val id = cursor.getLong(idIndex)
|
val id = cursor.getLong(idIndex)
|
||||||
|
@ -84,17 +85,22 @@ class MusicRepository {
|
||||||
MediaMetadataRetriever.METADATA_KEY_GENRE
|
MediaMetadataRetriever.METADATA_KEY_GENRE
|
||||||
)
|
)
|
||||||
|
|
||||||
val year = (retriever.extractMetadata(
|
val year = (
|
||||||
|
retriever.extractMetadata(
|
||||||
MediaMetadataRetriever.METADATA_KEY_YEAR
|
MediaMetadataRetriever.METADATA_KEY_YEAR
|
||||||
) ?: "0").toInt()
|
) ?: "0"
|
||||||
|
).toInt()
|
||||||
|
|
||||||
// Track is formatted as X/0, so trim off the /0 part to parse
|
// Track is formatted as X/0, so trim off the /0 part to parse
|
||||||
// the track number correctly.
|
// the track number correctly.
|
||||||
val track = (retriever.extractMetadata(
|
val track = (
|
||||||
|
retriever.extractMetadata(
|
||||||
MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER
|
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(
|
val duration = retriever.extractMetadata(
|
||||||
MediaMetadataRetriever.METADATA_KEY_DURATION
|
MediaMetadataRetriever.METADATA_KEY_DURATION
|
||||||
)!!.toLong()
|
)!!.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()
|
retriever.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +133,6 @@ class MusicRepository {
|
||||||
)
|
)
|
||||||
|
|
||||||
return songList
|
return songList
|
||||||
|
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
// TODO: Add better error handling
|
// TODO: Add better error handling
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue