很多Android开发可能知道, LayoutInflater.inflate()方法是个耗时操作, 应尽量避免调用.
我也曾经非常担心在Adapter和ViewGroup动态循环添加View时耗时太多, 但是感觉Android应该会有个布局xml的解析缓存, 今天看了下Android的源码, 果然如此. 在第一次调用inflate相应布局xml时会比较耗时, 之后就会很快!
下面贴上核心源码:
1. 在LayoutInflater中:
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
// 获取布局xml的parser
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
2. 在Resources中: @NonNull XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type) throws NotFoundException { final TypedValue value = obtainTempTypedValue(); try {
3. 在ResourcesImpl中, 首先读取缓存, 如果缓存中不存在, 再去实际读取文件, 解析加载 @NonNull XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, int assetCookie, @NonNull String type) throws NotFoundException { if (id != 0) { try { synchronized (mCachedXmlBlocks) { final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies; final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; // First see if this block is in our cache. final int num = cachedXmlBlockFiles.length; for (int i = 0; i < num; i++) { if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null && cachedXmlBlockFiles[i].equals(file)) { // 已经由缓存, 返回缓存 return cachedXmlBlocks[i].newParser(); } } // 没缓存, 解析加载 // Not in the cache, create a new block and put it at // the next slot in the cache. final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); if (block != null) { final int pos = (mLastCachedXmlBlockIndex + 1) % num; mLastCachedXmlBlockIndex = pos; final XmlBlock oldBlock = cachedXmlBlocks[pos]; if (oldBlock != null) { oldBlock.close(); } cachedXmlBlockCookies[pos] = assetCookie; cachedXmlBlockFiles[pos] = file; cachedXmlBlocks[pos] = block; return block.newParser(); } } } catch (Exception e) { final NotFoundException rnf = new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } } throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); }
final ResourcesImpl impl = mResourcesImpl; impl.getValue(id, value, true); if (value.type == TypedValue.TYPE_STRING) { // 用ResourcesImpl 实际获取布局xml的Parser return impl.loadXmlResourceParser(value.string.toString(), id, value.assetCookie, type); } throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) + " type #0x" + Integer.toHexString(value.type) + " is not valid"); } finally { releaseTempTypedValue(value); } }