Android Coil3缩略图、默认占位图placeholder、error加载错误体现,Kotlin(5)
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
- <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
复制代码
- implementation("io.coil-kt.coil3:coil:3.1.0")
- implementation("io.coil-kt.coil3:coil-gif:3.1.0")
- implementation("io.coil-kt.coil3:coil-core:3.1.0")
复制代码
- import android.content.ContentUris
- import android.content.Context
- import android.net.Uri
- import android.os.Bundle
- import android.provider.MediaStore
- import android.util.Log
- import androidx.appcompat.app.AppCompatActivity
- import androidx.lifecycle.lifecycleScope
- import androidx.recyclerview.widget.GridLayoutManager
- import androidx.recyclerview.widget.LinearLayoutManager
- import androidx.recyclerview.widget.RecyclerView
- import coil3.imageLoader
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.launch
- class MainActivity : AppCompatActivity() {
- companion object {
- const val SPAN_COUNT = 8
- const val THUMB_WIDTH = 20
- const val THUMB_HEIGHT = 20
- const val IMAGE_SIZE = 400
- const val TAG = "fly/MainActivity"
- }
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- val rv = findViewById<RecyclerView>(R.id.rv)
- val layoutManager = GridLayoutManager(this, SPAN_COUNT)
- layoutManager.orientation = LinearLayoutManager.VERTICAL
- val adapter = ImageAdapter(this, application.imageLoader)
- rv.adapter = adapter
- rv.layoutManager = layoutManager
- rv.setItemViewCacheSize(SPAN_COUNT * 2)
- rv.recycledViewPool.setMaxRecycledViews(0, SPAN_COUNT * 2)
- val ctx = this
- lifecycleScope.launch(Dispatchers.IO) {
- val imgList = readAllImage(ctx)
- val videoList = readAllVideo(ctx)
- Log.d(TAG, "readAllImage size=${imgList.size}")
- Log.d(TAG, "readAllVideo size=${videoList.size}")
- val lists = arrayListOf<MyData>()
- lists.addAll(imgList)
- lists.addAll(videoList)
- lists.shuffle()
- lifecycleScope.launch(Dispatchers.Main) {
- adapter.dataChanged(lists)
- }
- }
- }
- class MyData(var path: String, var uri: Uri)
- private fun readAllImage(ctx: Context): ArrayList<MyData> {
- val photos = ArrayList<MyData>()
- //读取所有图
- val cursor = ctx.contentResolver.query(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null
- )
- while (cursor!!.moveToNext()) {
- //路径
- val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA))
- val id = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)
- val imageUri: Uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(id))
- //名称
- //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, imageUri))
- }
- cursor.close()
- return photos
- }
- private fun readAllVideo(context: Context): ArrayList<MyData> {
- val videos = ArrayList<MyData>()
- //读取视频Video
- val cursor = context.contentResolver.query(
- MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
- null,
- null,
- null,
- null
- )
- while (cursor!!.moveToNext()) {
- //路径
- val path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))
- val id = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)
- val videoUri: Uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(id))
- //名称
- //val name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME))
- //大小
- //val size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE))
- videos.add(MyData(path, videoUri))
- }
- cursor.close()
- return videos
- }
- }
复制代码
- import android.app.Application
- import android.util.Log
- import coil3.ImageLoader
- import coil3.PlatformContext
- import coil3.SingletonImageLoader
- class MyApp : Application(), SingletonImageLoader.Factory {
- companion object {
- const val TAG = "fly/MyApp"
- }
- override fun newImageLoader(context: PlatformContext): ImageLoader {
- Log.d(TAG, "newImageLoader")
- return MyCoilManager.INSTANCE().getImageLoader(this)
- }
- }
复制代码
- import android.content.Context
- import android.graphics.Bitmap
- import android.os.Environment
- import android.util.Log
- import coil3.ImageLoader
- import coil3.disk.DiskCache
- import coil3.disk.directory
- import coil3.gif.AnimatedImageDecoder
- import coil3.memory.MemoryCache
- import coil3.request.CachePolicy
- import coil3.request.bitmapConfig
- import java.io.File
- class MyCoilManager {
- companion object {
- const val TAG = "fly/MyCoilManager"
- private val single by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { MyCoilManager() }
- fun INSTANCE() = single
- }
- private var mImageLoader: ImageLoader? = null
- fun getImageLoader(ctx: Context): ImageLoader {
- if (mImageLoader != null) {
- Log.w(TAG, "ImageLoader已经初始化")
- return mImageLoader!!
- }
- Log.d(TAG, "初始化ImageLoader")
- //初始化加载器。
- mImageLoader = ImageLoader.Builder(ctx)
- .memoryCachePolicy(CachePolicy.ENABLED)
- .memoryCache(initMemoryCache())
- .diskCachePolicy(CachePolicy.ENABLED)
- .diskCache(initDiskCache())
- .bitmapConfig(Bitmap.Config.ARGB_8888)
- .components {
- add(AnimatedImageDecoder.Factory())
- add(ThumbFetcher.Factory(ctx))
- }.build()
- Log.d(TAG, "memoryCache.maxSize=${mImageLoader!!.memoryCache?.maxSize}")
- return mImageLoader!!
- }
- private fun initMemoryCache(): MemoryCache {
- //内存缓存。
- val memoryCache = MemoryCache.Builder()
- .maxSizeBytes(1024 * 1024 * 1024 * 2L) //2GB
- .build()
- return memoryCache
- }
- private fun initDiskCache(): DiskCache {
- //磁盘缓存。
- val diskCacheFolder = Environment.getExternalStorageDirectory()
- val diskCacheName = "coil_disk_cache"
- val cacheFolder = File(diskCacheFolder, diskCacheName)
- if (cacheFolder.exists()) {
- Log.d(TAG, "${cacheFolder.absolutePath} exists")
- } else {
- if (cacheFolder.mkdir()) {
- Log.d(TAG, "${cacheFolder.absolutePath} create OK")
- } else {
- Log.e(TAG, "${cacheFolder.absolutePath} create fail")
- }
- }
- val diskCache = DiskCache.Builder()
- .maxSizeBytes(1024 * 1024 * 1024 * 2L) //2GB
- .directory(cacheFolder)
- .build()
- Log.d(TAG, "cache folder = ${diskCache.directory.toFile().absolutePath}")
- return diskCache
- }
- }
复制代码
- import android.content.Context
- import android.graphics.Bitmap
- import android.graphics.BitmapFactory
- import android.util.Log
- import android.view.View
- import android.view.ViewGroup
- import androidx.appcompat.widget.AppCompatImageView
- import androidx.recyclerview.widget.RecyclerView
- import coil3.Image
- import coil3.ImageLoader
- import coil3.asImage
- import coil3.memory.MemoryCache
- import coil3.request.Disposable
- import coil3.request.ImageRequest
- import coil3.request.SuccessResult
- import coil3.request.target
- import coil3.toBitmap
- class ImageAdapter : RecyclerView.Adapter<ImageHolder> {
- private var mCtx: Context? = null
- private var mImageLoader: ImageLoader? = null
- private var mViewSize = 0
- private var mPlaceholderImage: Image? = null
- private var mErrorBmp: Bitmap? = null
- companion object {
- const val TAG = "fly/ImageAdapter"
- }
- constructor(ctx: Context, il: ImageLoader?) : super() {
- mCtx = ctx
- mImageLoader = il
- mViewSize = mCtx!!.resources.displayMetrics.widthPixels / MainActivity.SPAN_COUNT
- mPlaceholderImage = BitmapFactory.decodeResource(mCtx!!.resources, android.R.drawable.ic_menu_gallery).asImage()
- mErrorBmp = BitmapFactory.decodeResource(mCtx!!.resources, android.R.drawable.stat_notify_error)
- }
- private var mItems = ArrayList<MainActivity.MyData>()
- fun dataChanged(items: ArrayList<MainActivity.MyData>) {
- this.mItems = items
- notifyDataSetChanged()
- }
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageHolder {
- val view = MyIV(mCtx!!, mViewSize)
- return ImageHolder(view)
- }
- override fun getItemCount(): Int {
- return mItems.size
- }
- override fun onBindViewHolder(holder: ImageHolder, position: Int) {
- val data = mItems[position]
- loadItemWithThumbForImage(data, holder.image)
- }
- private fun loadItemWithThumbForImage(data: MainActivity.MyData, myIv: MyIV) {
- val thumbItem = Item(uri = data.uri, path = data.path)
- thumbItem.type = Item.THUMB
- val thumbMemoryCacheKey = MemoryCache.Key(thumbItem.toString())
- val thumbMemoryCache = getMemoryCache(thumbMemoryCacheKey)
- val imageItem = Item(uri = data.uri, path = data.path)
- imageItem.type = Item.IMG
- val imageMemoryCacheKey = MemoryCache.Key(imageItem.toString())
- val imageMemoryCache = getMemoryCache(imageMemoryCacheKey)
- var isHighQualityLoaded = false
- var thumbDisposable: Disposable? = null
- //首次加载,没有正图缓存,也没有缩略图缓存。
- if (thumbMemoryCache == null && imageMemoryCache == null) {
- val thumbReq = ImageRequest.Builder(mCtx!!)
- .data(thumbItem)
- .memoryCacheKey(thumbMemoryCacheKey)
- .listener(object : ImageRequest.Listener {
- override fun onSuccess(request: ImageRequest, result: SuccessResult) {
- if (!isHighQualityLoaded) {
- myIv.setImageBitmap(result.image.toBitmap())
- }
- }
- }).build()
- thumbDisposable = mImageLoader?.enqueue(thumbReq)
- }
- var imgPlaceholder = mPlaceholderImage
- if (thumbMemoryCache != null) {
- imgPlaceholder = thumbMemoryCache.image
- }
- //无论如何,都要加载正图。
- val imageReq = ImageRequest.Builder(mCtx!!)
- .data(data.uri)
- .memoryCacheKey(imageMemoryCacheKey)
- .size(MainActivity.IMAGE_SIZE)
- .target(myIv)
- .placeholder(imgPlaceholder)
- .error(mErrorBmp!!.asImage())
- .listener(object : ImageRequest.Listener {
- override fun onSuccess(request: ImageRequest, result: SuccessResult) {
- isHighQualityLoaded = true
- thumbDisposable?.dispose()
- Log.d(TAG, "image onSuccess ${result.dataSource} $imageItem ${calMemoryCache()}")
- }
- }).build()
- mImageLoader?.enqueue(imageReq)
- }
- private fun getMemoryCache(key: MemoryCache.Key): MemoryCache.Value? {
- return mImageLoader?.memoryCache?.get(key)
- }
- private fun calMemoryCache(): String {
- return "${mImageLoader?.memoryCache?.size} / ${mImageLoader?.memoryCache?.maxSize}"
- }
- }
- class ImageHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- var image = itemView as MyIV
- }
- class MyIV : AppCompatImageView {
- companion object {
- const val TAG = "fly/MyIV"
- }
- private var mSize = 0
- private var mCtx: Context? = null
- constructor(ctx: Context, size: Int) : super(ctx) {
- mCtx = ctx
- mSize = size
- scaleType = ScaleType.CENTER_CROP
- }
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- setMeasuredDimension(mSize, mSize)
- }
- }
复制代码
- import android.net.Uri
- class Item {
- companion object {
- const val THUMB = 0
- const val IMG = 1
- }
- var uri: Uri? = null
- var path: String? = null
- var lastModified = 0L
- var width = 0
- var height = 0
- var position = -1
- var type = -1 //0,缩略图。 1,正图image。-1,未知。
- constructor(uri: Uri, path: String) {
- this.uri = uri
- this.path = path
- }
- override fun toString(): String {
- return "Item(uri=$uri, path=$path, lastModified=$lastModified, width=$width, height=$height, position=$position, type=$type)"
- }
- }
复制代码
- import android.content.Context
- import android.graphics.Bitmap
- import android.util.Log
- import android.util.Size
- import coil3.ImageLoader
- import coil3.asImage
- import coil3.decode.DataSource
- import coil3.fetch.FetchResult
- import coil3.fetch.Fetcher
- import coil3.fetch.ImageFetchResult
- import coil3.request.Options
- /**
- * 例如 FileUriFetcher
- */
- class ThumbFetcher(private val ctx: Context, private val thumbItem: Item, private val options: Options) : Fetcher {
- companion object {
- const val TAG = "fly/ThumbFetcher"
- }
- override suspend fun fetch(): FetchResult {
- var bmp: Bitmap? = null
- val t = System.currentTimeMillis()
- try {
- bmp = ctx.contentResolver.loadThumbnail(thumbItem.uri!!, Size(MainActivity.THUMB_WIDTH, MainActivity.THUMB_HEIGHT), null)
- Log.d(TAG, "loadThumbnail time cost=${System.currentTimeMillis() - t} $thumbItem")
- } catch (e: Exception) {
- Log.e(TAG, "e=$e ThumbItem=$thumbItem")
- }
- return ImageFetchResult(
- bmp?.asImage()!!,
- true,
- dataSource = DataSource.DISK
- )
- }
- class Factory(private val ctx: Context) : Fetcher.Factory<Item> {
- override fun create(
- data: Item,
- options: Options,
- imageLoader: ImageLoader,
- ): Fetcher {
- return ThumbFetcher(ctx, data, options)
- }
- }
- }
复制代码
Android Coil3缩略图、默认占位图placeholder、error加载错误体现,Kotlin(4)_android coil 图片加载框架,设置占位图后,图片的比例不正确-CSDN博客文章欣赏阅读786次,点赞19次,收藏10次。遗留标题,设置的disk cache似乎没有work,指定的磁盘缓存文件路径天生是天生了,但是app跑起来运行后(图正常体现),内里是空的。遗留标题,设置的disk cache似乎没有work,指定的磁盘缓存文件路径天生是天生了,但是app跑起来运行后(图正常体现),内里是空的。遗留标题,设置的disk cache似乎没有work,指定的磁盘缓存文件路径天生是天生了,但是app跑起来运行后(图正常体现),内里是空的。2、现在分别利用缩略图内存缓存和正图内存缓存,感觉应该可以归并,只利用一套内存缓存。_android coil 图片加载框架,设置占位图后,图片的比例不正确 https://blog.csdn.net/zhangphil/article/details/145832225
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|