glide ModelLoader的Key错误使用 可能造成的内存泄漏
业务场景
之前项目性能优化,在自定义的AppGlideModule中的registerComponents方法append了自定义ModelLoaderFactory,然后有很多个File对象出现了内存泄漏,后面定位到以下场景,代码如下:
kotlin
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.signature.ObjectKey
import com.fawvw.hmi.media.mediacommon.model.mediadata.AudioMediaData
import java.io.InputStream
class AudioModuleLoader : ModelLoader<AudioMediaData, InputStream> {
override fun buildLoadData(
model: AudioMediaData,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream> {
val path = if (model.albumArt != null) {
"${model.artist}${model.duration}${model.album}"
} else {
model.uri
}
return ModelLoader.LoadData(ObjectKey(path), AudioCoverFetcher(model))
}
//这里使用了AudioCoverSignature
return ModelLoader.LoadData(AudioCoverSignature(path), AudioCoverFetcher(model))
}
override fun handles(model: AudioMediaData) = true
}
kotlin
import com.bumptech.glide.load.Key
import java.io.File
import java.security.MessageDigest
class AudioCoverSignature(private val path:String): Key {
private val stringBuilder by lazy {
StringBuilder()
}
//这个file内存泄漏了
private val file by lazy {
File(path)
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
stringBuilder.append(file.lastModified()).append(file.absolutePath)
val bs = stringBuilder.toString().encodeToByteArray()
messageDigest.update(bs, 0, bs.size)
}
}
泄露的原因是因为,AudioCoverSignature类只重写了updateDiskCacheKey方法,没有重写equals方法,而ModelLoader.LoadData方法的入参key是用来找缓存的,每一个都找不到,导致内存泄漏
kotlin
/**
* Contains a set of {@link com.bumptech.glide.load.Key Keys} identifying the source of the load,
* alternate cache keys pointing to equivalent data, and a {@link
* com.bumptech.glide.load.data.DataFetcher} that can be used to fetch data not found in cache.
*
* @param <Data> The type of data that well be loaded.
*/
class LoadData<Data> {
public final Key sourceKey;
public final List<Key> alternateKeys;
public final DataFetcher<Data> fetcher;
...
解决方法
将自定义AudioCoverSignature删除,使用ObjectKey解决此问题
kotlin
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.signature.ObjectKey
import com.fawvw.hmi.media.mediacommon.model.mediadata.AudioMediaData
import java.io.InputStream
class AudioModuleLoader : ModelLoader<AudioMediaData, InputStream> {
override fun buildLoadData(
model: AudioMediaData,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<InputStream> {
val path = if (model.albumArt != null) {
"${model.artist}${model.duration}${model.album}"
} else {
model.uri
}
//这里使用ObjectKey
return ModelLoader.LoadData(ObjectKey(path), AudioCoverFetcher(model))
}
override fun handles(model: AudioMediaData) = true
}
问题解决了