android应用图片加载与存放目录分析

本文详细分析了Android应用中使用资源ID加载图片的流程,包括Context、Resources、Drawable和Bitmap的生成步骤。同时,通过三个测试探讨了图片在不同drawable/mipmap目录下生成Bitmap的大小关系,揭示了图片存放目录对加载效果的影响。最后,提供了优化图片加载的建议,如选择合适的目录存放切图,利用BitmapFactory.Options进行内存优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文分析的代码版本为Android 6.0

请尊重博主劳动成果,转载请标明出处。

一 使用资源id加载加载图片流程

在Activity或Fragment中常使用getResources().getDrawable()加载图片资源。getResources和getDrawable方法的调用需要经过哪些步骤和流程。

1 与Context相关的步骤

ContextThemeWrapper的

    @Override
    public Resources getResources() {
        return getResourcesInternal();
    }

    private Resources getResourcesInternal() {
        if (mResources == null) {
            if (mOverrideConfiguration == null) {
                mResources = super.getResources();
            } else {
                final Context resContext = createConfigurationContext(mOverrideConfiguration);
                mResources = resContext.getResources();
            }
        }
        return mResources;
    }

只分析mOverrideConfiguration==null条件下如何获取resource。super.getResources()调用的是ContextWrapper的方法,而ContextWrapper调用的是mBase.getResources()。mBase是ContextImpl实例,在Activity被ActivityThread创建时,通过Activity的attach()方法赋值给Activity的。Activity和ContextImpl的创建和赋值过程这里就不分析了。
ContextImpl的getResources()方法:

    @Override
    public Resources getResources() {
        return mResources;
    }

而mResources是在ContextImpl的私有构造方法内创建的。

   private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
            Display display, Configuration overrideConfiguration, int createDisplayWithId) {
        …//省略部分无关代码
        mMainThread = mainThread;
        mActivityToken = activityToken;
        mFlags = flags;

        if (user == null) {
            user = Process.myUserHandle();
        }
        mUser = user;

        mPackageInfo = packageInfo;
        mResourcesManager = ResourcesManager.getInstance();

        final int displayId = (createDisplayWithId != Display.INVALID_DISPLAY)
                ? createDisplayWithId
                : (display != null) ? display.getDisplayId() : Display.DEFAULT_DISPLAY;

        CompatibilityInfo compatInfo = null;
        if (container != null) {
            compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
        }
        if (compatInfo == null) {
            compatInfo = (displayId == Display.DEFAULT_DISPLAY)
                    ? packageInfo.getCompatibilityInfo()
                    : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
        }
        //创建
        Resources resources = packageInfo.getResources(mainThread);
        if (resources != null) {
            if (displayId != Display.DEFAULT_DISPLAY
                    || overrideConfiguration != null
                    || (compatInfo != null && compatInfo.applicationScale
                            != resources.getCompatibilityInfo().applicationScale)) {

                if (container != null) {
                    // This is a nested Context, so it can't be a base Activity context.
                    // Just create a regular Resources object associated with the Activity.
                    resources = mResourcesManager.getResources(
                            activityToken,
                            packageInfo.getResDir(),
                            packageInfo.getSplitResDirs(),
                            packageInfo.getOverlayDirs(),
                            packageInfo.getApplicationInfo().sharedLibraryFiles,
                            displayId,
                            overrideConfiguration,
                            compatInfo,
                            packageInfo.getClassLoader());
                } else {
                    // This is not a nested Context, so it must be the root Activity context.
                    // All other nested Contexts will inherit the configuration set here.
                    //创建Activity的Context时的赋值流程
                    resources = mResourcesManager.createBaseActivityResources(
                            activityToken,
                            packageInfo.getResDir(),
                            packageInfo.getSplitResDirs(),
                            packageInfo.getOverlayDirs(),
                            packageInfo.getApplicationInfo().sharedLibraryFiles,
                            displayId,
                            overrideConfiguration,
                            compatInfo,
                            packageInfo.getClassLoader());
                }
            }
        }
        mResources = resources;

        …//省略部分无关代码
    }

这里就不分析packageInfo.getResources,mResourcesManager.getResources和mResourcesManager.createBaseActivityResources如何创建Resources。

2 Resources和ResourcesImpl中的步骤

继续看Resources#getDrawable:

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值