Android 与“碰撞”;尝试使用回收的位图“;使用Glide4.11,转换会导致这种情况吗?
我知道已经有很多问题与“尝试使用回收的位图”崩溃有关,但没有一个对我有帮助 详情:Android 与“碰撞”;尝试使用回收的位图“;使用Glide4.11,转换会导致这种情况吗?,android,kotlin,Android,Kotlin,我知道已经有很多问题与“尝试使用回收的位图”崩溃有关,但没有一个对我有帮助 详情: 此项目中的任何位置都没有对Bitmap.recycle()的调用 使用Glide(4.11.0)加载所有图像 Glide调用都很简单,不使用占位符 在切换片段时,崩溃似乎是随机发生的 我唯一能想到的就是这些转变。 此项目中只有2个转换 CircletTransformation(将图像剪辑为具有自定义半径的圆): 和ClipWhiteTransformation(从图像中删除白色边框): 类ClipHiteT
- 此项目中的任何位置都没有对Bitmap.recycle()的调用
- 使用Glide(4.11.0)加载所有图像
- Glide调用都很简单,不使用占位符
- 在切换片段时,崩溃似乎是随机发生的
类ClipHiteTransformation():BitmapTransformation(){
伴星{
private const val ID=“com.project.transformation.clipWhite”
私有值ID_字节:ByteArray=ID.toByteArray()
//配置
const val white=253//白色像素,如果所有通道都等于或大于此值
const val transparent=50//透明像素,如果小于此值
}
公共覆盖乐趣转换(池:BitmapPool,源:位图,向外宽:Int,向外高:Int):位图{
val width=source.width-1
val高度=source.height-1
val halfX=宽度/2
val halfY=高度/2
var startY=0
//左边缘
左变量=0
用于(0中的x直到半x){
val pixel=source.getPixel(x,halfY)
//透明的?
如果(颜色alpha(像素)<透明)继续
//不是白人?
if(Color.red(像素)2){
startY=2
}
打破
}
}
//右边距
var right=0
用于(0中的x直到半x){
val pixel=source.getPixel(宽度-x,半像素)
//透明的?
如果(颜色alpha(像素)<透明)继续
//不是白人?
if(Color.red(像素)2){
startY=2
}
打破
}
}
//上边距
var top=0
对于(从星形到半星形){
val pixel=source.getPixel(halfX,y)
//透明的?
如果(颜色alpha(像素)<透明)继续
//不是白人?
if(Color.red(像素)abs(newHeight-outHeight))outWidth/newWidth.toFloat()其他outHeight/newHeight.toFloat()值
val矩阵=矩阵()。应用{setScale(scale,scale)}
返回Bitmap.createBitmap(源、左、上、新宽度、新高度、矩阵、假)
}
//缓存帮助程序
覆盖乐趣等于(其他:任何?):布尔值{
返回other is ClipWhiteTransformation&&other.hashCode()==hashCode()
}
重写哈希代码():Int{
返回ID.hashCode()
}
重写fun updateDiskCacheKey(messageDigest:messageDigest){
messageDigest.update(ID_字节)
}
}
最初使用BitmapPool时,删除它并没有阻止崩溃
顺便说一下,这是用于加载图像的扩展:
fun ImageView.setURL(url: String,
@DrawableRes error: Int? = null,
@DrawableRes placeholder: Int? = null,
size: Int? = null,
options: ((RequestBuilder<Drawable>) -> Unit)? = null,
completion: ((resource: Drawable?) -> Unit)? = null) {
// No URL, use Placeholder if exists, if not, use the error image
if (url.isEmpty()) {
placeholder?.also{ setImageResource(it) } ?: run { error?.also{ setImageResource(it) } }
return
}
Glide.with(applicationInstance) // (I'm using an application instance directly here)
.load(url).apply {
completion?.also { completion ->
this.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
completion(null)
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
completion(resource)
return false
}
})
}
}
.apply { size?.also { this.override(it)} }
.apply { options?.invoke(this) }
.placeholder(placeholder ?: 0)
.error(error ?: 0)
.transition(DrawableTransitionOptions.withCrossFade(350))
.into(this)
}
fun ImageView.setURL(url:String,
@DrawableRes错误:Int?=null,
@DrawableRes占位符:Int?=null,
大小:Int?=null,
选项:((RequestBuilder)->Unit)?=null,
完成:((资源:可提取?->单位)?=null){
//没有URL,请使用占位符(如果存在),如果没有,请使用错误图像
if(url.isEmpty()){
占位符?.allow{setImageResource(it)}?:运行{error?.allow{setImageResource(it)}
返回
}
with(applicationInstance)//(我在这里直接使用一个应用程序实例)
.load(url).应用{
完成?也是{完成->
this.listener(对象:RequestListener{
重写fun onLoadFailed(e:GlideException?,model:Any?,target:target?,isFirstResource:Boolean):布尔{
完成(空)
返回错误
}
覆盖onResourceReady(资源:可绘制?、模型:任意?、目标:目标?、数据源:数据源?、isFirstResource:Boolean):布尔{
完成(资源)
返回错误
}
})
}
}
.apply{size?。同时{this.override(it)}
.apply{options?.invoke(this)}
.占位符(占位符?:0)
.错误(错误?:0)
.过渡(可绘制过渡选项,带交叉渐变(350))
.进入(这个)
}
很抱歉在这里粘贴了这么多代码(希望对其他人有用)。
这些变换或加载程序会导致崩溃吗?塑造(圆形/方形/椭圆形)
你不喜欢的图像
class ClipWhiteTransformation() : BitmapTransformation() {
companion object {
private const val ID = "com.project.transformation.clipWhite"
private val ID_BYTES: ByteArray = ID.toByteArray()
// Config
const val white = 253 // White pixel, if all channels are equal or greater than this
const val transparent = 50 // Transparent pixel, if Less than this
}
public override fun transform(pool: BitmapPool, source: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val width = source.width - 1
val height = source.height - 1
val halfX = width / 2
val halfY = height / 2
var startY = 0
// Left Margin
var left = 0
for (x in 0 until halfX) {
val pixel = source.getPixel(x, halfY)
// Transparent?
if (Color.alpha(pixel) < transparent) continue
// Not white?
if (Color.red(pixel) < white || Color.green(pixel) < white || Color.blue(pixel) < white) {
left = x
if (x > 2) {
startY = 2
}
break
}
}
// Right Margin
var right = 0
for (x in 0 until halfX) {
val pixel = source.getPixel(width - x, halfY)
// Transparent?
if (Color.alpha(pixel) < transparent) continue
// Not white?
if (Color.red(pixel) < white || Color.green(pixel) < white || Color.blue(pixel) < white) {
right = x
if (x > 2) {
startY = 2
}
break
}
}
// Top Margin
var top = 0
for (y in startY until halfY) {
val pixel = source.getPixel(halfX, y)
// Transparent?
if (Color.alpha(pixel) < transparent) continue
// Not white?
if (Color.red(pixel) < white || Color.green(pixel) < white || Color.blue(pixel) < white) {
top = y
break
}
}
// Bottom Margin
var bottom = 0
for (y in startY until halfY) {
val pixel = source.getPixel(halfX, height - y)
// Transparent?
if (Color.alpha(pixel) < transparent) continue
// Not white?
if (Color.red(pixel) < white || Color.green(pixel) < white || Color.blue(pixel) < white) {
bottom = y
break
}
}
// Clip, scale and return
val newWidth = width - (left + right)
val newHeight = height - (top + bottom)
val scale = if (abs(newWidth - outWidth) > abs(newHeight - outHeight)) outWidth / newWidth.toFloat() else outHeight / newHeight.toFloat()
val matrix = Matrix().apply { setScale(scale, scale) }
return Bitmap.createBitmap(source, left, top, newWidth, newHeight, matrix, false)
}
// Caching helpers
override fun equals(other: Any?): Boolean {
return other is ClipWhiteTransformation && other.hashCode() == hashCode()
}
override fun hashCode(): Int {
return ID.hashCode()
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(ID_BYTES)
}
}
fun ImageView.setURL(url: String,
@DrawableRes error: Int? = null,
@DrawableRes placeholder: Int? = null,
size: Int? = null,
options: ((RequestBuilder<Drawable>) -> Unit)? = null,
completion: ((resource: Drawable?) -> Unit)? = null) {
// No URL, use Placeholder if exists, if not, use the error image
if (url.isEmpty()) {
placeholder?.also{ setImageResource(it) } ?: run { error?.also{ setImageResource(it) } }
return
}
Glide.with(applicationInstance) // (I'm using an application instance directly here)
.load(url).apply {
completion?.also { completion ->
this.listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
completion(null)
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
completion(resource)
return false
}
})
}
}
.apply { size?.also { this.override(it)} }
.apply { options?.invoke(this) }
.placeholder(placeholder ?: 0)
.error(error ?: 0)
.transition(DrawableTransitionOptions.withCrossFade(350))
.into(this)
}
implementation 'com.google.android.material:material:1.3.0-alpha01'
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/imgStudent"
android:layout_width="100dp"
android:layout_height="100dp"
app:shapeAppearanceOverlay="@style/circleImageView"
android:padding="2dp"
app:strokeColor="@color/white"
app:strokeWidth="5dp"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
tools:srcCompat="@drawable/ic_kid_placeholder"
/>
<style name="circleImageView" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">50%</item>
<item name="android:shadowRadius">100</item>
<item name="android:shadowColor">@color/gray</item>
<item name="backgroundOverlayColorAlpha">12</item>
</style>