赞
踩
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
- plugins {
- id 'org.jetbrains.kotlin.kapt'
- }
-
-
- implementation 'com.github.bumptech.glide:glide:4.16.0'
- kapt 'com.github.bumptech.glide:compiler:4.16.0'
- import android.content.Context
- import android.util.Log
- import com.bumptech.glide.GlideBuilder
- import com.bumptech.glide.annotation.GlideModule
- import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
- import com.bumptech.glide.load.engine.cache.MemorySizeCalculator
- import com.bumptech.glide.load.engine.executor.GlideExecutor
- import com.bumptech.glide.module.AppGlideModule
-
-
- @GlideModule
- class MyGlideModule : AppGlideModule() {
-
- override fun applyOptions(context: Context, builder: GlideBuilder) {
- super.applyOptions(context, builder)
- builder.setLogLevel(Log.DEBUG)
-
- val memoryCacheScreens = 200F
- val maxSizeMultiplier = 0.8F
-
- val calculator = MemorySizeCalculator.Builder(context)
- .setMemoryCacheScreens(memoryCacheScreens)
- .setBitmapPoolScreens(memoryCacheScreens)
- .setMaxSizeMultiplier(maxSizeMultiplier)
- .setLowMemoryMaxSizeMultiplier(maxSizeMultiplier * 0.8F)
- .setArrayPoolSize((1024 * 1024 * memoryCacheScreens).toInt())
- .build()
-
- builder.setMemorySizeCalculator(calculator)
-
- val diskCacheSize = 1024 * 1024 * 2000L
- builder.setDiskCache(InternalCacheDiskCacheFactory(context, diskCacheSize))
-
-
- val mSourceExecutor = GlideExecutor.newSourceBuilder()
- .setUncaughtThrowableStrategy(GlideExecutor.UncaughtThrowableStrategy.LOG)
- .setThreadCount(4)
- //.setThreadTimeoutMillis(1000) //线程读写超时时间。
- .setName("fly-SourceExecutor")
- .build()
-
- val mDiskCacheBuilder = GlideExecutor.newDiskCacheBuilder()
- .setThreadCount(1)
- //.setThreadTimeoutMillis(1000) //线程读写超时时间。
- .setName("fly-DiskCacheBuilder")
- .build()
-
- val mAnimationExecutor = GlideExecutor.newDiskCacheBuilder()
- .setThreadCount(1)
- //.setThreadTimeoutMillis(1000) //线程读写超时时间。
- .setName("fly-AnimationExecutor")
- .build()
-
- builder.setSourceExecutor(mSourceExecutor)
- builder.setDiskCacheExecutor(mDiskCacheBuilder)
- builder.setAnimationExecutor(mAnimationExecutor)
- }
-
- override fun isManifestParsingEnabled(): Boolean {
- return false
- }
- }
- import android.content.Context
- import android.os.Bundle
- import android.provider.MediaStore
- import android.util.Log
- import android.view.View
- import android.view.ViewGroup
- import androidx.appcompat.app.AppCompatActivity
- import androidx.appcompat.widget.AppCompatImageView
- import androidx.lifecycle.lifecycleScope
- import androidx.recyclerview.widget.GridLayoutManager
- import androidx.recyclerview.widget.LinearLayoutManager
- import androidx.recyclerview.widget.RecyclerView
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.launch
- import kotlinx.coroutines.withContext
-
-
- class MainActivity : AppCompatActivity() {
- companion object {
- const val TAG = "fly"
-
- const val VIEW_TYPE = 0
-
- const val PRELOAD_HEIGHT_COUNT = 2
- const val IMAGE_SIZE = 200
- const val ITEM_VIEW_CACHE_SIZE = 30
- const val SPAN_COUNT = 8
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
-
- val rv = findViewById<RecyclerView>(R.id.rv)
- val layoutManager = MyLayoutManager(this, SPAN_COUNT)
- layoutManager.orientation = LinearLayoutManager.VERTICAL
- rv.layoutManager = layoutManager
-
- val adapter = MyAdapter(this)
- rv.adapter = adapter
-
- rv.setHasFixedSize(true)
- rv.setItemViewCacheSize(ITEM_VIEW_CACHE_SIZE)
-
- lifecycleScope.launch(Dispatchers.IO) {
- val items = readAllImage(this@MainActivity)
- withContext(Dispatchers.Main) {
- adapter.dataChanged(items)
- }
- }
-
- val ctx = this
- rv.setRecyclerListener(object : RecyclerView.RecyclerListener {
- override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
- val h: MyVH? = holder as? MyVH
- if (h != null) {
- GlideApp.with(ctx).clear(h.image!!)
- }
-
- Log.d(TAG, "${h?.adapterPosition} onViewRecycled")
- }
- })
- }
-
- class MyAdapter : RecyclerView.Adapter<MyVH> {
- private var items = arrayListOf<MyData>()
- private var mContext: Context? = null
-
- constructor(ctx: Context) {
- this.mContext = ctx
- }
-
- fun dataChanged(items: ArrayList<MyData>) {
- this.items = items
- notifyDataSetChanged()
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyVH {
- val view = MyImageView(mContext!!)
- return MyVH(view)
- }
-
- override fun getItemCount(): Int {
- return items.size
- }
-
- override fun getItemViewType(position: Int): Int {
- return VIEW_TYPE
- }
-
- override fun onBindViewHolder(holder: MyVH, position: Int) {
- Log.d(TAG, "onBindViewHolder $position")
-
- val uri = items[holder.adapterPosition].path
-
- GlideApp.with(mContext!!)
- .asBitmap()
- .load(uri)
- .centerCrop()
- .override(IMAGE_SIZE, IMAGE_SIZE)
- .into(holder.image!!)
- }
- }
-
- class MyVH : RecyclerView.ViewHolder {
- var image: MyImageView? = null
-
- constructor(itemView: View) : super(itemView) {
- //image.layoutParams.height= IMAGE_SIZE
- //image.layoutParams.width= IMAGE_SIZE
- image = itemView as MyImageView
- }
- }
-
- class MyImageView : AppCompatImageView {
- constructor(ctx: Context) : super(ctx) {
-
- }
- }
-
- class MyLayoutManager : GridLayoutManager {
- constructor(ctx: Context, spanCount: Int) : super(ctx, spanCount) {
-
- }
-
- override fun getExtraLayoutSpace(state: RecyclerView.State?): Int {
- return PRELOAD_HEIGHT_COUNT * IMAGE_SIZE
- }
- }
-
-
- class MyData(var path: String, var index: Int)
-
- private fun readAllImage(context: Context): ArrayList<MyData> {
- val photos = ArrayList<MyData>()
-
- //读取所有图片
- val cursor = context.contentResolver.query(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null
- )
-
- var index = 0
- while (cursor!!.moveToNext()) {
- //路径 uri
- val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
-
- //图片名称
- //val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME))
- //图片大小
- //val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE))
-
- photos.add(MyData(path, index++))
- }
- cursor.close()
-
- return photos
- }
- }
避免使用xml定义ImageView装配到ViewHolder,这种情况在8宫格和更大宫格情况下,IO耗时,卡顿现象明显。
上面这种方式实现较为简洁、易懂,如果还要持续优化,想要更快,还有更复杂的方式:Android Glide自定义AppCompatImageView切分成若干小格子,每个小格子onDraw绘制Bitmap,Kotlin(1)_android appcompatimageview-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。