ImageView在setImageResource后发生了什么

源码解析

调用Resources.getDrawableForDensity 获取对应分辨率下的图片,这个时候如果我们在不同的分辨率文件下的图片不一样,在不同的手机分辨率下就会显示不同的图片。

java 复制代码
@Nullable
public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
    final TypedValue value = obtainTempTypedValue();
    try {
        final ResourcesImpl impl = mResourcesImpl;
        impl.getValueForDensity(id, density, value, true);
        return loadDrawable(value, id, density, theme);
    } finally {
        releaseTempTypedValue(value);
    }
}

@NonNull
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Drawable loadDrawable(@NonNull TypedValue value, int id, int density, @Nullable Theme theme)
        throws NotFoundException {
    return mResourcesImpl.loadDrawable(this, value, id, density, theme);
}

如果不是对应类型的Drawable(ColorDrawable),就会调用 loadDrawableForCookie 去加载指定Id的图像文件。

java 复制代码
// ResourcesImpl#loadDrawable

// Next, check preloaded drawables. Preloaded drawables may contain
// unresolved theme attributes.
final Drawable.ConstantState cs;
if (isColorDrawable) {
    cs = sPreloadedColorDrawables.get(key);
} else {
    cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
}

Drawable dr;
boolean needsNewDrawableAfterCache = false;
if (cs != null) {
    dr = cs.newDrawable(wrapper);
} else if (isColorDrawable) {
    dr = new ColorDrawable(value.data);
} else {
    dr = loadDrawableForCookie(wrapper, value, id, density);
}
java 复制代码
 /**
* Loads a drawable from XML or resources stream.
*
* @return Drawable, or null if Drawable cannot be decoded.
*/
@Nullable
private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
        int id, int density) {
    if (value.string == null) {
        throw new NotFoundException("Resource "" + getResourceName(id) + "" ("
                + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
    }
    ...

    final Drawable dr;

    LookupStack stack = mLookupStack.get();
    try {
        // Perform a linear search to check if we have already referenced this resource before.
        if (stack.contains(id)) {
            throw new Exception("Recursive reference in drawable");
        }
        stack.push(id);
        try {
            if (file.endsWith(".xml")) {
                // 加载XML图像文件
                final String typeName = getResourceTypeName(id);
                if (typeName != null && typeName.equals("color")) {
                    dr = loadColorOrXmlDrawable(wrapper, value, id, density, file);
                } else {
                    dr = loadXmlDrawable(wrapper, value, id, density, file);
                }
            } else {
                // 加载其他的图像文件,jpg\png
                final InputStream is = mAssets.openNonAsset(
                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
                final AssetInputStream ais = (AssetInputStream) is;
                dr = decodeImageDrawable(ais, wrapper, value);
            }
        } finally {
            stack.pop();
        }
    } catch (Exception | StackOverflowError e) {
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        final NotFoundException rnf = new NotFoundException(
                "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
        rnf.initCause(e);
        throw rnf;
    }
    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);

    return dr;
}

/**
* Loads a Drawable from an encoded image stream, or null.
*
* This call will handle closing ais.
*/
@Nullable
private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,
        @NonNull Resources wrapper, @NonNull TypedValue value) {
    ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
                        wrapper, value);
    try {
        return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
            decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
        });
    } catch (IOException ioe) {
        // This is okay. This may be something that ImageDecoder does not
        // support, like SVG.
        return null;
    }
}

在下面这个方法中对非XML格式的图像文件进行加载,会先调用native方法对图像文件进行解码,创建Bitmap对象,将数据加载到native中。

java 复制代码
@WorkerThread
@NonNull
private static Drawable decodeDrawableImpl(@NonNull Source src,
        @Nullable OnHeaderDecodedListener listener) throws IOException {
    try (ImageDecoder decoder = src.createImageDecoder(true /*preferAnimation*/)) {
        decoder.mSource = src;
        decoder.callHeaderDecoded(listener, src);

        try (ImageDecoderSourceTrace unused = new ImageDecoderSourceTrace(decoder)) {
            // ...
            // this call potentially manipulates the decoder so it must be performed prior to
            // decoding the bitmap and after decode set the density on the resulting bitmap
            final int srcDensity = decoder.computeDensity(src);
            
            // 动态图, gif
            if (decoder.mAnimated) {
                // AnimatedImageDrawable calls postProcessAndRelease only if
                // mPostProcessor exists.
                ImageDecoder postProcessPtr = decoder.mPostProcessor == null ? null : decoder;
                decoder.checkState(true);
                Drawable d = new AnimatedImageDrawable(decoder.mNativePtr,
                        postProcessPtr, decoder.mDesiredWidth,
                        decoder.mDesiredHeight, decoder.getColorSpacePtr(),
                        decoder.checkForExtended(), srcDensity,
                        src.computeDstDensity(), decoder.mCropRect,
                        decoder.mInputStream, decoder.mAssetFd);
                // d has taken ownership of these objects.
                decoder.mInputStream = null;
                decoder.mAssetFd = null;
                return d;
            }

            // 解码图片数据,加载bitmap
            Bitmap bm = decoder.decodeBitmapInternal();
            bm.setDensity(srcDensity);

            //...
            
            // 默认 BitmapDrawable
            return new BitmapDrawable(res, bm);
        }
    } finally {
        // Close the ImageDecoder#decode trace.
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    }
}

问题

  1. BitmapDrawable中的bitmap 在什么时候会回收native中的数据?

从分析源码的情况,BitmapDrawable 并不会因为引用BD其他View的销毁而会被recycle。所以我们在设置Bitmap结束后,最好还是在整体视图被销毁后,主动调用recycle(),释放native数据

相关推荐
进击的CJR1 小时前
MySQL 8.0 OCP 英文题库解析(三)
android·mysql·开闭原则
Mckay885 小时前
android studio导入项目
android·ide·android studio
是店小二呀7 小时前
【优选算法 | 字符串】字符串模拟题精选:思维+实现解析
android·c++·算法
weixin_473894777 小时前
前端服务器部署分类总结
前端·网络·性能优化
奔跑吧 android8 小时前
【android bluetooth 协议分析 12】【A2DP详解 1】【车机侧蓝牙音乐免切源介绍】
android·bluetooth·bt·gd·a2dpsink·免切源·aosp14
飞猿_SIR9 小时前
Android Exoplayer多路不同时长音视频混合播放
android·音视频
前端懒猫9 小时前
android实现USB通讯
android
jiet_h10 小时前
Android锁
android
东方未明010812 小时前
docker(一)前言:高并发服务端技术架构的演进
docker·性能优化·高并发·虚拟化·容器化
teacher伟大光荣且正确19 小时前
Qt Creator 配置 Android 编译环境
android·开发语言·qt