From 53382b44bb7ab7ccb559e96fd1f93c47020878ee Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Wed, 2 Aug 2017 16:21:49 -0700 Subject: Improve video prefetching (#17) * Create base activity and add thumbnails to media picker * Add checker to see if requested permission is inside the manifest * Add faq parser with tests * Add kpref testers and expose sp * Test jitpack sample exclusion * Test caching * Improve glide caching --- .../ca/allanwang/kau/mediapicker/MediaItem.kt | 1 + .../ca/allanwang/kau/mediapicker/MediaItemBasic.kt | 1 + .../allanwang/kau/mediapicker/MediaPickerBinder.kt | 7 ++++ .../allanwang/kau/mediapicker/MediaPickerCore.kt | 46 ++++++++++++++++++---- 4 files changed, 48 insertions(+), 7 deletions(-) (limited to 'mediapicker/src/main/kotlin') diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt index 3947809..b6f3721 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItem.kt @@ -40,6 +40,7 @@ class MediaItem(val data: MediaModel) super.bindView(holder, payloads) Glide.with(holder.itemView) .load(data.data) + .applyMediaOptions(holder.itemView.context) .listener(object : RequestListener { override fun onLoadFailed(e: GlideException?, model: Any, target: Target, isFirstResource: Boolean): Boolean { failedToLoad = true diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt index 4fbe955..c28ed29 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaItemBasic.kt @@ -47,6 +47,7 @@ class MediaItemBasic(val data: MediaModel) super.bindView(holder, payloads) Glide.with(holder.itemView) .load(data.data) + .applyMediaOptions(holder.itemView.context) .listener(object : RequestListener { override fun onLoadFailed(e: GlideException?, model: Any, target: Target, isFirstResource: Boolean): Boolean { holder.image.setImageDrawable(MediaPickerCore.getErrorDrawable(holder.itemView.context)) diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt index bdd25ba..cb218fc 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerBinder.kt @@ -1,8 +1,12 @@ package ca.allanwang.kau.mediapicker import android.app.Activity +import android.content.Context import android.content.Intent import ca.allanwang.kau.utils.startActivityForResult +import com.bumptech.glide.RequestBuilder +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions /** * Created by Allan Wang on 2017-07-21. @@ -31,3 +35,6 @@ internal const val MEDIA_PICKER_RESULT = "media_picker_result" internal const val ANIMATION_DURATION = 200L internal const val ANIMATION_SCALE = 0.95f +internal fun RequestBuilder.applyMediaOptions(context: Context) + = apply(RequestOptions().diskCacheStrategy(DiskCacheStrategy.RESOURCE).centerCrop().override(MediaPickerCore.viewSize(context))) + diff --git a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt index 255cec4..ee3481d 100644 --- a/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt +++ b/mediapicker/src/main/kotlin/ca/allanwang/kau/mediapicker/MediaPickerCore.kt @@ -12,34 +12,42 @@ import android.provider.MediaStore import android.support.v4.app.LoaderManager import android.support.v4.content.CursorLoader import android.support.v4.content.Loader -import android.support.v7.app.AppCompatActivity import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.RecyclerView import ca.allanwang.kau.animators.FadeScaleAnimatorAdd import ca.allanwang.kau.animators.KauAnimator +import ca.allanwang.kau.internal.KauBaseActivity +import ca.allanwang.kau.kotlin.lazyContext import ca.allanwang.kau.permissions.kauRequestPermissions import ca.allanwang.kau.utils.dimenPixelSize import ca.allanwang.kau.utils.toast +import com.bumptech.glide.Glide import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.IconicsDrawable +import org.jetbrains.anko.doAsync +import java.util.concurrent.ExecutionException +import java.util.concurrent.Future /** * Created by Allan Wang on 2017-07-23. * * Container for the main logic behind the both pickers */ -abstract class MediaPickerCore>(val mediaType: MediaType) : AppCompatActivity(), LoaderManager.LoaderCallbacks { +abstract class MediaPickerCore>( + val mediaType: MediaType, val preload: Boolean = mediaType == MediaType.VIDEO +) : KauBaseActivity(), LoaderManager.LoaderCallbacks { companion object { + val viewSize = lazyContext { computeViewSize(it) } /** * Given the dimensions of our device and a minimum image size, * Computer the optimal column count for our grid layout * * @return column count */ - fun computeColumnCount(context: Context): Int { + private fun computeColumnCount(context: Context): Int { val minImageSizePx = context.dimenPixelSize(R.dimen.kau_image_minimum_size) val screenWidthPx = context.resources.displayMetrics.widthPixels return screenWidthPx / minImageSizePx @@ -48,7 +56,7 @@ abstract class MediaPickerCore>(val mediaType: MediaType) : AppC /** * Compute our resulting image size */ - fun computeViewSize(context: Context): Int { + private fun computeViewSize(context: Context): Int { val screenWidthPx = context.resources.displayMetrics.widthPixels return screenWidthPx / computeColumnCount(context) } @@ -84,6 +92,9 @@ abstract class MediaPickerCore>(val mediaType: MediaType) : AppC const val CACHE_SIZE = 80 } + private var hasPreloaded = false + private var prefetcher: Future<*>? = null + val adapter: FastItemAdapter = FastItemAdapter() /** @@ -140,13 +151,30 @@ abstract class MediaPickerCore>(val mediaType: MediaType) : AppC onStatusChange(false) return } - val items = mutableListOf() + val models = mutableListOf() do { val model = MediaModel(data) if (!shouldLoad(model)) continue - items.add(converter(model)) + models.add(model) } while (data.moveToNext()) - addItems(items) + addItems(models.map { converter(it) }) + if (!hasPreloaded && preload) { + hasPreloaded = true + prefetcher = doAsync { + models.subList(0, Math.min(models.size, 50)).map { it.data }.forEach { + val target = Glide.with(this@MediaPickerCore).load(it) + .applyMediaOptions(this@MediaPickerCore) + .submit() + try { + target.get() + } catch (ignored: InterruptedException) { + } catch (ignored: ExecutionException) { + } finally { + Glide.with(this@MediaPickerCore).clear(target) + } + } + } + } } abstract fun converter(model: MediaModel): T @@ -179,4 +207,8 @@ abstract class MediaPickerCore>(val mediaType: MediaType) : AppC open fun onStatusChange(loaded: Boolean) {} + override fun onDestroy() { + prefetcher?.cancel(true) + super.onDestroy() + } } \ No newline at end of file -- cgit v1.2.3