Loading core/java/android/view/LayoutInflater.java +182 −79 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.res.XmlResourceParser; import android.graphics.Canvas; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; Loading @@ -37,6 +38,9 @@ import android.widget.FrameLayout; import com.android.internal.R; import dalvik.system.PathClassLoader; import java.io.File; import java.lang.reflect.Method; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -71,6 +75,10 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY = "view.precompiled_layout_enabled"; private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex"; /** Empty stack trace used to avoid log spam in re-throw exceptions. */ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; Loading @@ -92,6 +100,13 @@ public abstract class LayoutInflater { private Factory2 mPrivateFactory; private Filter mFilter; // Indicates whether we should try to inflate layouts using a precompiled layout instead of // inflating from the XML resource. private boolean mUseCompiledView; // This variable holds the classloader that will be used to look for precompiled layouts. The // The classloader includes the generated compiled_view.dex file. private ClassLoader mPrecompiledClassLoader; @UnsupportedAppUsage final Object[] mConstructorArgs = new Object[2]; Loading Loading @@ -214,6 +229,7 @@ public abstract class LayoutInflater { */ protected LayoutInflater(Context context) { mContext = context; initPrecompiledViews(); } /** Loading @@ -230,6 +246,7 @@ public abstract class LayoutInflater { mFactory2 = original.mFactory2; mPrivateFactory = original.mPrivateFactory; setFilter(original.mFilter); initPrecompiledViews(); } /** Loading Loading @@ -371,6 +388,29 @@ public abstract class LayoutInflater { } } private void initPrecompiledViews() { try { mUseCompiledView = SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false); if (mUseCompiledView) { mPrecompiledClassLoader = mContext.getClassLoader(); String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME; if (new File(dexFile).exists()) { mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader); } else { // If the precompiled layout file doesn't exist, then disable precompiled // layouts. mUseCompiledView = false; } } } catch (Throwable e) { if (DEBUG) { Log.e(TAG, "Failed to initialized precompiled views layouts", e); } mUseCompiledView = false; } } /** * Inflate a new view hierarchy from the specified xml resource. Throws * {@link InflateException} if there is an error. Loading Loading @@ -430,7 +470,11 @@ public abstract class LayoutInflater { + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); View view = tryInflatePrecompiled(resource, res, root, attachToRoot); if (view != null) { return view; } XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { Loading @@ -438,6 +482,73 @@ public abstract class LayoutInflater { } } private @Nullable View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root, boolean attachToRoot) { if (!mUseCompiledView) { return null; } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)"); // Try to inflate using a precompiled layout. String pkg = res.getResourcePackageName(resource); String layout = res.getResourceEntryName(resource); try { Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView"); Method inflater = clazz.getMethod(layout, Context.class, int.class); View view = (View) inflater.invoke(null, mContext, resource); if (view != null && root != null) { // We were able to use the precompiled inflater, but now we need to do some work to // attach the view to the root correctly. XmlResourceParser parser = res.getLayout(resource); try { AttributeSet attrs = Xml.asAttributeSet(parser); advanceToRootNode(parser); ViewGroup.LayoutParams params = root.generateLayoutParams(attrs); if (attachToRoot) { root.addView(view, params); } else { view.setLayoutParams(params); } } finally { parser.close(); } } return view; } catch (Throwable e) { if (DEBUG) { Log.e(TAG, "Failed to use precompiled view", e); } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } return null; } /** * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is * found. */ private void advanceToRootNode(XmlPullParser parser) throws InflateException, IOException, XmlPullParserException { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } } /** * Inflate a new view hierarchy from the specified XML node. Throws * {@link InflateException} if there is an error. Loading Loading @@ -471,18 +582,7 @@ public abstract class LayoutInflater { View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } advanceToRootNode(parser); final String name = parser.getName(); if (DEBUG) { Loading Loading @@ -985,6 +1085,9 @@ public abstract class LayoutInflater { + "reference. The layout ID " + value + " is not valid."); } final View precompiled = tryInflatePrecompiled(layout, context.getResources(), (ViewGroup) parent, /*attachToRoot=*/true); if (precompiled == null) { final XmlResourceParser childParser = context.getResources().getLayout(layout); try { Loading Loading @@ -1060,7 +1163,7 @@ public abstract class LayoutInflater { } finally { childParser.close(); } } LayoutInflater.consumeChildElements(parser); } Loading Loading
core/java/android/view/LayoutInflater.java +182 −79 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.res.XmlResourceParser; import android.graphics.Canvas; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; Loading @@ -37,6 +38,9 @@ import android.widget.FrameLayout; import com.android.internal.R; import dalvik.system.PathClassLoader; import java.io.File; import java.lang.reflect.Method; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; Loading Loading @@ -71,6 +75,10 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY = "view.precompiled_layout_enabled"; private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex"; /** Empty stack trace used to avoid log spam in re-throw exceptions. */ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; Loading @@ -92,6 +100,13 @@ public abstract class LayoutInflater { private Factory2 mPrivateFactory; private Filter mFilter; // Indicates whether we should try to inflate layouts using a precompiled layout instead of // inflating from the XML resource. private boolean mUseCompiledView; // This variable holds the classloader that will be used to look for precompiled layouts. The // The classloader includes the generated compiled_view.dex file. private ClassLoader mPrecompiledClassLoader; @UnsupportedAppUsage final Object[] mConstructorArgs = new Object[2]; Loading Loading @@ -214,6 +229,7 @@ public abstract class LayoutInflater { */ protected LayoutInflater(Context context) { mContext = context; initPrecompiledViews(); } /** Loading @@ -230,6 +246,7 @@ public abstract class LayoutInflater { mFactory2 = original.mFactory2; mPrivateFactory = original.mPrivateFactory; setFilter(original.mFilter); initPrecompiledViews(); } /** Loading Loading @@ -371,6 +388,29 @@ public abstract class LayoutInflater { } } private void initPrecompiledViews() { try { mUseCompiledView = SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false); if (mUseCompiledView) { mPrecompiledClassLoader = mContext.getClassLoader(); String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME; if (new File(dexFile).exists()) { mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader); } else { // If the precompiled layout file doesn't exist, then disable precompiled // layouts. mUseCompiledView = false; } } } catch (Throwable e) { if (DEBUG) { Log.e(TAG, "Failed to initialized precompiled views layouts", e); } mUseCompiledView = false; } } /** * Inflate a new view hierarchy from the specified xml resource. Throws * {@link InflateException} if there is an error. Loading Loading @@ -430,7 +470,11 @@ public abstract class LayoutInflater { + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); View view = tryInflatePrecompiled(resource, res, root, attachToRoot); if (view != null) { return view; } XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { Loading @@ -438,6 +482,73 @@ public abstract class LayoutInflater { } } private @Nullable View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root, boolean attachToRoot) { if (!mUseCompiledView) { return null; } Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)"); // Try to inflate using a precompiled layout. String pkg = res.getResourcePackageName(resource); String layout = res.getResourceEntryName(resource); try { Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView"); Method inflater = clazz.getMethod(layout, Context.class, int.class); View view = (View) inflater.invoke(null, mContext, resource); if (view != null && root != null) { // We were able to use the precompiled inflater, but now we need to do some work to // attach the view to the root correctly. XmlResourceParser parser = res.getLayout(resource); try { AttributeSet attrs = Xml.asAttributeSet(parser); advanceToRootNode(parser); ViewGroup.LayoutParams params = root.generateLayoutParams(attrs); if (attachToRoot) { root.addView(view, params); } else { view.setLayoutParams(params); } } finally { parser.close(); } } return view; } catch (Throwable e) { if (DEBUG) { Log.e(TAG, "Failed to use precompiled view", e); } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } return null; } /** * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is * found. */ private void advanceToRootNode(XmlPullParser parser) throws InflateException, IOException, XmlPullParserException { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } } /** * Inflate a new view hierarchy from the specified XML node. Throws * {@link InflateException} if there is an error. Loading Loading @@ -471,18 +582,7 @@ public abstract class LayoutInflater { View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } advanceToRootNode(parser); final String name = parser.getName(); if (DEBUG) { Loading Loading @@ -985,6 +1085,9 @@ public abstract class LayoutInflater { + "reference. The layout ID " + value + " is not valid."); } final View precompiled = tryInflatePrecompiled(layout, context.getResources(), (ViewGroup) parent, /*attachToRoot=*/true); if (precompiled == null) { final XmlResourceParser childParser = context.getResources().getLayout(layout); try { Loading Loading @@ -1060,7 +1163,7 @@ public abstract class LayoutInflater { } finally { childParser.close(); } } LayoutInflater.consumeChildElements(parser); } Loading