Skip to content

Commit

Permalink
Merge pull request #159 from TeamAmaze/feature-preloader-improv
Browse files Browse the repository at this point in the history
Improvements in preloader for better performance
  • Loading branch information
VishalNehra committed Dec 26, 2023
2 parents 743edce + ddcb4d6 commit b536b0f
Show file tree
Hide file tree
Showing 18 changed files with 140 additions and 104 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Expand Up @@ -2,7 +2,7 @@ buildscript {
ext {
jacocoVersion = "0.8.7"
androidXLifecycleVersion = "2.3.1"
glideVersion = '4.11.0'
glideVersion = '4.16.0'
fragment_version = "1.3.6"
roomVersion = "2.4.0"
billing_version = "6.0.1"
Expand Down
Expand Up @@ -261,7 +261,7 @@ interface IAudioPlayerInterfaceHandler : OnPlaybackInfoUpdate, LifecycleOwner {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
// do nothing
Expand All @@ -274,15 +274,15 @@ interface IAudioPlayerInterfaceHandler : OnPlaybackInfoUpdate, LifecycleOwner {
}

override fun onResourceReady(
resource: Drawable?,
model: Any?,
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
getContextWeakRef().get()?.let {
context ->
resource?.let {
resource.let {
getAudioPlayerHandlerViewModel().getPaletteColor(
it,
context.getColor(R.color.navy_blue_alt_3)
Expand Down
Expand Up @@ -35,7 +35,7 @@ import java.lang.ref.WeakReference
class ReviewAnalysisAdapter(
val context: Context,
val analysisType: Int?,
private val preloader: MediaAdapterPreloader,
private val preloader: MediaAdapterPreloader<MediaFileInfo>,
private val mediaFileInfoList: MutableList<MediaFileInfo>,
toggleCheckCallback: (
checkedSize: Int,
Expand All @@ -55,10 +55,10 @@ class ReviewAnalysisAdapter(
value.clear()
for (i in mediaFileInfoList.indices) {
value.add(ListItem(mediaFileInfo = mediaFileInfoList[i]))
preloader.addItem(mediaFileInfoList[i].path)
preloader.addItem(mediaFileInfoList[i])
}
if (mediaFileInfoList.size != 0) {
preloader.addItem("")
preloader.addItem(null)
value.add(ListItem(EMPTY_LAST_ITEM))
}
field = value
Expand Down
Expand Up @@ -68,8 +68,8 @@ class ReviewImagesFragment : ItemsActionBarFragment() {
private lateinit var viewModel: AnalyseViewModel
private var gridLayoutManager: GridLayoutManager? = GridLayoutManager(context, 3)
private var mediaFileAdapter: ReviewAnalysisAdapter? = null
private var preloader: MediaAdapterPreloader? = null
private var recyclerViewPreloader: RecyclerViewPreloader<String>? = null
private var preloader: MediaAdapterPreloader<MediaFileInfo>? = null
private var recyclerViewPreloader: RecyclerViewPreloader<MediaFileInfo>? = null
private val MAX_PRELOAD = 50
private var analysisType: Int? = null

Expand Down Expand Up @@ -146,9 +146,10 @@ class ReviewImagesFragment : ItemsActionBarFragment() {
// set list adapter
preloader = MediaAdapterPreloader(
requireContext(),
R.drawable.ic_outline_insert_drive_file_32
R.drawable.ic_outline_insert_drive_file_32,
true
)
val sizeProvider = ViewPreloadSizeProvider<String>()
val sizeProvider = ViewPreloadSizeProvider<MediaFileInfo>()
recyclerViewPreloader = RecyclerViewPreloader(
Glide.with(requireActivity()),
preloader!!,
Expand Down
Expand Up @@ -53,9 +53,10 @@ abstract class AbstractMediaInfoListFragment :
private var gridLayoutManager: GridLayoutManager? = null
private val MAX_PRELOAD = 100
private var log: Logger = LoggerFactory.getLogger(AbstractMediaInfoListFragment::class.java)
private var mediaPreloader: MediaAdapterPreloader<MediaFileInfo>? = null

override fun onDestroyView() {
getMediaAdapterPreloader().clear()
mediaPreloader?.clear()
super.onDestroyView()
}

Expand Down Expand Up @@ -83,7 +84,7 @@ abstract class AbstractMediaInfoListFragment :
abstract fun getFileStorageSummaryAndMediaFileInfoPair():
Pair<FilesViewModel.StorageSummary, List<MediaFileInfo>?>?

abstract fun getMediaAdapterPreloader(): MediaAdapterPreloader
abstract fun getMediaAdapterPreloader(isGrid: Boolean): MediaAdapterPreloader<MediaFileInfo>

abstract fun getRecyclerView(): RecyclerView

Expand Down Expand Up @@ -116,21 +117,22 @@ abstract class AbstractMediaInfoListFragment :
storageSummary.totalUsedSpace!!
)
// set list adapter
val sizeProvider = ViewPreloadSizeProvider<String>()
val recyclerViewPreloader = RecyclerViewPreloader(
Glide.with(requireActivity()),
getMediaAdapterPreloader(),
sizeProvider,
MAX_PRELOAD
)
val sizeProvider = ViewPreloadSizeProvider<MediaFileInfo>()
val isList = requireContext()
.getAppCommonSharedPreferences().getBoolean(
"${getMediaListType()}_${PreferencesConstants.KEY_MEDIA_LIST_TYPE}",
PreferencesConstants.DEFAULT_MEDIA_LIST_TYPE
)
mediaPreloader = getMediaAdapterPreloader(!isList)
val recyclerViewPreloader = RecyclerViewPreloader(
Glide.with(requireActivity()),
mediaPreloader!!,
sizeProvider,
MAX_PRELOAD
)
mediaFileAdapter = MediaFileAdapter(
requireActivity(),
getMediaAdapterPreloader(),
mediaPreloader!!,
this@AbstractMediaInfoListFragment, !isList,
MediaFileListSorter.SortingPreference.newInstance(
requireContext()
Expand Down
Expand Up @@ -72,8 +72,8 @@ class AudiosListFragment : AbstractMediaInfoListFragment(), IAudioPlayerInterfac
Pair<FilesViewModel.StorageSummary, List<MediaFileInfo>?>? = null

private lateinit var audioPlaybackServiceConnection: AudioPlaybackServiceConnection
private var filesPreloader: MediaAdapterPreloader? = null
private var playlistsPreloader: MediaAdapterPreloader? = null
private var filesPreloader: MediaAdapterPreloader<MediaFileInfo>? = null
private var playlistsPreloader: MediaAdapterPreloader<MediaFileInfo>? = null
private var isWaveformProcessing = false
private var lastPaletteColor: Int = 0
private var lastLyrics: String? = null
Expand Down Expand Up @@ -368,7 +368,7 @@ class AudiosListFragment : AbstractMediaInfoListFragment(), IAudioPlayerInterfac
}
}

override fun getMediaAdapterPreloader(): MediaAdapterPreloader {
override fun getMediaAdapterPreloader(isGrid: Boolean): MediaAdapterPreloader<MediaFileInfo> {
val sharedPrefs = requireContext().getAppCommonSharedPreferences()
val groupByPref = sharedPrefs.getInt(
MediaFileListSorter.SortingPreference.getGroupByKey(MediaFileAdapter.MEDIA_TYPE_AUDIO),
Expand All @@ -378,15 +378,17 @@ class AudiosListFragment : AbstractMediaInfoListFragment(), IAudioPlayerInterfac
if (filesPreloader == null) {
filesPreloader = MediaAdapterPreloader(
requireContext(),
R.drawable.ic_outline_audio_file_32
R.drawable.ic_outline_audio_file_32,
isGrid
)
}
return filesPreloader!!
} else {
if (playlistsPreloader == null) {
playlistsPreloader = MediaAdapterPreloader(
requireContext(),
R.drawable.ic_outline_audio_file_32
R.drawable.ic_outline_audio_file_32,
isGrid
)
}
return playlistsPreloader!!
Expand Down
Expand Up @@ -47,7 +47,7 @@ class DocumentsListFragment : AbstractMediaInfoListFragment() {
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private var preloader: MediaAdapterPreloader? = null
private var preloader: MediaAdapterPreloader<MediaFileInfo>? = null

override fun onCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -79,11 +79,12 @@ class DocumentsListFragment : AbstractMediaInfoListFragment() {
fileStorageSummaryAndMediaFileInfo else null
}

override fun getMediaAdapterPreloader(): MediaAdapterPreloader {
override fun getMediaAdapterPreloader(isGrid: Boolean): MediaAdapterPreloader<MediaFileInfo> {
if (preloader == null) {
preloader = MediaAdapterPreloader(
requireContext(),
R.drawable.ic_outline_insert_drive_file_32
R.drawable.ic_outline_insert_drive_file_32,
isGrid
)
}
return preloader!!
Expand Down
Expand Up @@ -50,8 +50,8 @@ class FilesFragment : ItemsActionBarFragment() {
private val filesViewModel: FilesViewModel by activityViewModels()
private var _binding: FragmentFilesBinding? = null
private var mediaFileAdapter: RecentMediaFilesAdapter? = null
private var preloader: MediaAdapterPreloader? = null
private var recyclerViewPreloader: RecyclerViewPreloader<String>? = null
private var preloader: MediaAdapterPreloader<MediaFileInfo>? = null
private var recyclerViewPreloader: RecyclerViewPreloader<MediaFileInfo>? = null
private var linearLayoutManager: LinearLayoutManager? = null
private val MAX_PRELOAD = 100

Expand Down Expand Up @@ -295,9 +295,10 @@ class FilesFragment : ItemsActionBarFragment() {
}
preloader = MediaAdapterPreloader(
applicationContext,
R.drawable.ic_outline_insert_drive_file_32
R.drawable.ic_outline_insert_drive_file_32,
false
)
val sizeProvider = ViewPreloadSizeProvider<String>()
val sizeProvider = ViewPreloadSizeProvider<MediaFileInfo>()
recyclerViewPreloader = RecyclerViewPreloader(
Glide.with(applicationContext),
preloader!!,
Expand Down
Expand Up @@ -47,7 +47,7 @@ class ImagesListFragment : AbstractMediaInfoListFragment() {
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private var preloader: MediaAdapterPreloader? = null
private var preloader: MediaAdapterPreloader<MediaFileInfo>? = null

override fun onCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -79,11 +79,12 @@ class ImagesListFragment : AbstractMediaInfoListFragment() {
fileStorageSummaryAndMediaFileInfo else null
}

override fun getMediaAdapterPreloader(): MediaAdapterPreloader {
override fun getMediaAdapterPreloader(isGrid: Boolean): MediaAdapterPreloader<MediaFileInfo> {
if (preloader == null) {
preloader = MediaAdapterPreloader(
requireContext(),
R.drawable.ic_outline_image_32
R.drawable.ic_outline_image_32,
isGrid
)
}
return preloader!!
Expand Down
Expand Up @@ -30,55 +30,52 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.ListPreloader.PreloadModelProvider
import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target

class MediaAdapterPreloader(private val context: Context, private val loadingDrawable: Int) :
PreloadModelProvider<String> {
private var request: RequestBuilder<Drawable> = Glide.with(context).asDrawable().fitCenter()
private var items: MutableList<String>? = null
class MediaAdapterPreloader<T : MediaFileInfo>(
private val context: Context,
private val loadingDrawable: Int,
private val isGrid: Boolean
) :
PreloadModelProvider<T> {
private var request: RequestBuilder<Drawable> = initRequestBuilder()
private var items: MutableList<T?>? = null

fun addItem(item: String) {
fun addItem(item: T?) {
if (items == null) {
items = arrayListOf()
}
items!!.add(item)
}

// be sure to call clear once you're done with this, to avoid memory leaks
fun clear() {
items?.clear()
}

override fun getPreloadItems(position: Int): List<String> {
if (items == null) return emptyList()
override fun getPreloadItems(position: Int): List<T?> {
if (items == null || items!![position] == null) return emptyList()
return listOf(items!![position])
}

override fun getPreloadRequestBuilder(item: String): RequestBuilder<*> {
return request.clone().fallback(R.drawable.ic_outline_broken_image_24)
.placeholder(loadingDrawable).load(item)
override fun getPreloadRequestBuilder(item: T): RequestBuilder<*> {
// return request.clone().fallback(R.drawable.ic_outline_broken_image_24)
// .placeholder(loadingDrawable).load(item)
// return request.load(item)
return getReadyRequestBuilder(item)
}

fun loadImage(item: MediaFileInfo, view: ImageView, isGrid: Boolean) {
val toLoadPath: String = item.path
val toLoadBitmap: Bitmap? = item.extraInfo?.audioMetaData?.albumArt
val toLoadDrawable = item.extraInfo?.apkMetaData?.drawable
var transformedRequest = request.fallback(R.drawable.ic_outline_broken_image_24)
.placeholder(loadingDrawable).load(toLoadDrawable ?: toLoadBitmap ?: toLoadPath)
if (toLoadBitmap == null) {
// apply size constraint when we don't have bitmap, as bitmap already is resized see CursorUtils
transformedRequest = transformedRequest
.apply(
RequestOptions().override(
if (isGrid) 500 else 100,
if (isGrid) 500 else 100
)
)
}
private fun initRequestBuilder(): RequestBuilder<Drawable> {
var transformedRequest = Glide.with(context).asDrawable()
.diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
.fallback(R.drawable.ic_outline_broken_image_24)
.placeholder(loadingDrawable).fitCenter()
transformedRequest = if (isGrid) {
transformedRequest.centerCrop()
.transform(CenterCrop(), GranularRoundedCorners(24.px, 24.px, 0f, 0f))
Expand All @@ -91,25 +88,54 @@ class MediaAdapterPreloader(private val context: Context, private val loadingDra
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
if (isGrid) {
view.setPadding(16.px.toInt(), 16.px.toInt(), 16.px.toInt(), 16.px.toInt())
// fallback drawable in case image fails to load.
// we add padding because svg placeholder is too big and looks ugly.
// view.setPadding(16.px.toInt(), 16.px.toInt(), 16.px.toInt(), 16.px.toInt())
}
return false
}

override fun onResourceReady(
resource: Drawable?,
model: Any?,
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
// do nothing
return false
}
}).into(view)
})
return transformedRequest
}

private fun getReadyRequestBuilder(item: MediaFileInfo): RequestBuilder<Drawable> {
var transformedRequest = request.load(getLoadingModel(item))
if (item.extraInfo?.audioMetaData?.albumArt == null) {
// apply size constraint when we don't have bitmap, as bitmap already is resized see CursorUtils
transformedRequest = transformedRequest
.apply(
RequestOptions().override(
if (isGrid) 250 else 100,
if (isGrid) 250 else 100
).diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
)
}
return transformedRequest
}

private fun getLoadingModel(mediaFileInfo: MediaFileInfo): Any {
val toLoadPath: String = mediaFileInfo.path
val toLoadBitmap: Bitmap? = mediaFileInfo.extraInfo?.audioMetaData?.albumArt
val toLoadDrawable = mediaFileInfo.extraInfo?.apkMetaData?.drawable
return toLoadDrawable ?: toLoadBitmap ?: toLoadPath
}

fun loadImage(item: MediaFileInfo, view: ImageView) {
getReadyRequestBuilder(item).into(view)
}
}

0 comments on commit b536b0f

Please sign in to comment.