Android 资源文件匹配规则

Android 资源文件匹配规则

Android 资源文件,可以加各种限定标注,类似我们常用的layout-hdpi ,layout-xhpdi,value-zh-rCN,layout-400x800等等。官方支持的请参考:
应用资源概览
那么Android是怎么去判断使用哪个一个呢?

资源查找

我们知道,不管定义多少个限制符的资源文件,ID只有一个,所以到底取哪个文件夹下面的呢?
以Resource#getDrawable开启。主要流程是:Resource#getDrawable-》Resource#getDrawableForDensity-》ResourcesImpl#getValueForDensity-》Resource#loadDrawable。关键性的选择是在ResourcesImpl#getValueForDensity。

这里进入的是AssetManager#getResourceValue。看源码:

 @UnsupportedAppUsage
    boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
            boolean resolveRefs) {
        Objects.requireNonNull(outValue, "outValue");
        synchronized (this) {
            ensureValidLocked();
            final int cookie = nativeGetResourceValue(
                    mObject, resId, (short) densityDpi, outValue, resolveRefs);
            if (cookie <= 0) {
                return false;
            }

            // Convert the changing configurations flags populated by native code.
            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
                    outValue.changingConfigurations);

            if (outValue.type == TypedValue.TYPE_STRING) {
                outValue.string = getPooledStringForCookie(cookie, outValue.data);
            }
            return true;
        }
    }

这个方法是不给外部使用的,真正干活的是nativeGetResourceValue(
mObject, resId, (short) densityDpi, outValue, resolveRefs);
下面就是真正的源码了,必须下载aosp.

//Volumes/AOSP/aosp/frameworks/base/core/jni/android_util_AssetManager.cpp   
static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
                                  jshort density, jobject typed_value,
                                  jboolean resolve_references) {
 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
 Res_value value;
 ResTable_config selected_config;
 uint32_t flags;
 ApkAssetsCookie cookie =
     assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
                               static_cast<uint16_t>(density), &value, &selected_config, &flags);
 if (cookie == kInvalidCookie) {
   return ApkAssetsCookieToJavaCookie(kInvalidCookie);
 }
 ....
 }

具体的分析就不继续了,我给大家贴下需要的文件路径。

/Volumes/AOSP/aosp/frameworks/base/libs/androidfw/AssetManager2.cpp
/Volumes/AOSP/aosp/frameworks/base/libs/androidfw/ResourceTypes.cpp

那么上面那个多限定符的优先级是在哪里确定的?

 //Volumes/AOSP/aosp/frameworks/base/libs/androidfw/AssetManager2.cpp
 ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
                                        bool /*stop_at_first_match*/,
                                        bool ignore_configuration,
                                        FindEntryResult* out_entry) const {
.....

if (!overlay_result.config.isBetterThan(out_entry->config, desired_config)
         && overlay_result.config.compare(out_entry->config) != 0) {
       // The configuration of the entry for the overlay must be equal to or better than the target
       // configuration to be chosen as the better value.
       continue;
     }
.....
}

//Volumes/AOSP/aosp/frameworks/base/libs/androidfw/ResourceTypes.cpp
bool ResTable_config::isBetterThan(const ResTable_config& o,
       const ResTable_config* requested){
if (imsi || o.imsi) {
           if ((mcc != o.mcc) && requested->mcc) {
               return (mcc);
           }

           if ((mnc != o.mnc) && requested->mnc) {
               return (mnc);
           }
       }

       if (isLocaleBetterThan(o, requested)) {
           return true;
       }

       if (screenLayout || o.screenLayout) {
           if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
                   && (requested->screenLayout & MASK_LAYOUTDIR)) {
               int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
               int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
               return (myLayoutDir > oLayoutDir);
           }
       }

       if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
           // The configuration closest to the actual size is best.
           // We assume that larger configs have already been filtered
           // out at this point.  That means we just want the largest one.
           if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
               return smallestScreenWidthDp > o.smallestScreenWidthDp;
           }
       }

       if (screenSizeDp || o.screenSizeDp) {
           // "Better" is based on the sum of the difference between both
           // width and height from the requested dimensions.  We are
           // assuming the invalid configs (with smaller dimens) have
           // already been filtered.  Note that if a particular dimension
           // is unspecified, we will end up with a large value (the
           // difference between 0 and the requested dimension), which is
           // good since we will prefer a config that has specified a
           // dimension value.
           int myDelta = 0, otherDelta = 0;
           if (requested->screenWidthDp) {
               myDelta += requested->screenWidthDp - screenWidthDp;
               otherDelta += requested->screenWidthDp - o.screenWidthDp;
           }
           if (requested->screenHeightDp) {
               myDelta += requested->screenHeightDp - screenHeightDp;
               otherDelta += requested->screenHeightDp - o.screenHeightDp;
           }
           if (kDebugTableSuperNoisy) {
               ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
                       screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
                       requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
           }
           if (myDelta != otherDelta) {
               return myDelta < otherDelta;
           }
       }

       if (screenLayout || o.screenLayout) {
           if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
                   && (requested->screenLayout & MASK_SCREENSIZE)) {
               // A little backwards compatibility here: undefined is
               // considered equivalent to normal.  But only if the
               // requested size is at least normal; otherwise, small
               // is better than the default.
               int mySL = (screenLayout & MASK_SCREENSIZE);
               int oSL = (o.screenLayout & MASK_SCREENSIZE);
               int fixedMySL = mySL;
               int fixedOSL = oSL;
               if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
                   if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
                   if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
               }
               // For screen size, the best match is the one that is
               // closest to the requested screen size, but not over
               // (the not over part is dealt with in match() below).
               if (fixedMySL == fixedOSL) {
                   // If the two are the same, but 'this' is actually
                   // undefined, then the other is really a better match.
                   if (mySL == 0) return false;
                   return true;
               }
               if (fixedMySL != fixedOSL) {
                   return fixedMySL > fixedOSL;
               }
           }
           if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
                   && (requested->screenLayout & MASK_SCREENLONG)) {
               return (screenLayout & MASK_SCREENLONG);
           }
       }

       if (screenLayout2 || o.screenLayout2) {
           if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
                   (requested->screenLayout2 & MASK_SCREENROUND)) {
               return screenLayout2 & MASK_SCREENROUND;
           }
       }

       if (colorMode || o.colorMode) {
           if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0 &&
                   (requested->colorMode & MASK_WIDE_COLOR_GAMUT)) {
               return colorMode & MASK_WIDE_COLOR_GAMUT;
           }
           if (((colorMode^o.colorMode) & MASK_HDR) != 0 &&
                   (requested->colorMode & MASK_HDR)) {
               return colorMode & MASK_HDR;
           }
       }

       if ((orientation != o.orientation) && requested->orientation) {
           return (orientation);
       }

       if (uiMode || o.uiMode) {
           if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
                   && (requested->uiMode & MASK_UI_MODE_TYPE)) {
               return (uiMode & MASK_UI_MODE_TYPE);
           }
           if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
                   && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
               return (uiMode & MASK_UI_MODE_NIGHT);
           }
       }

       if (screenType || o.screenType) {
       。。。。。。。。


 if (screenSize || o.screenSize) {
           // "Better" is based on the sum of the difference between both
           // width and height from the requested dimensions.  We are
           // assuming the invalid configs (with smaller sizes) have
           // already been filtered.  Note that if a particular dimension
           // is unspecified, we will end up with a large value (the
           // difference between 0 and the requested dimension), which is
           // good since we will prefer a config that has specified a
           // size value.
           int myDelta = 0, otherDelta = 0;
           if (requested->screenWidth) {
               myDelta += requested->screenWidth - screenWidth;
               otherDelta += requested->screenWidth - o.screenWidth;
           }
           if (requested->screenHeight) {
               myDelta += requested->screenHeight - screenHeight;
               otherDelta += requested->screenHeight - o.screenHeight;
           }
           if (myDelta != otherDelta) {
               return myDelta < otherDelta;
           }
       }
       。。。。。。
}

ResourceTypes.cpp 里面来判断匹配和匹配规则。
所以,限定符的顺序,必须按照上面贴的那个链接顺序来,解析的时候也是按照那个优先级来处理的。其中要说一下,这里还有个判断screenSize,就是我们填写的400x800,我不知道官方为啥把这部分拿掉了,可能是不希望我们这么做吧。

关于screenSize 这个好像是要减去状态栏,这个等我找找是在哪里的定义?

具体比如说,hdpi xhdpi优先级确定,这个部分在isBetterThan方法里面有描述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值