diff options
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/view/LayoutInflater.java | 93 |
2 files changed, 77 insertions, 18 deletions
diff --git a/api/current.txt b/api/current.txt index abab90182b01..66a4bd096aea 100644 --- a/api/current.txt +++ b/api/current.txt @@ -49550,6 +49550,7 @@ package android.view { ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context); method public abstract android.view.LayoutInflater cloneInContext(android.content.Context); method public final android.view.View createView(String, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; + method @Nullable public final android.view.View createView(@NonNull android.content.Context, @NonNull String, @Nullable String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException; method public static android.view.LayoutInflater from(android.content.Context); method public android.content.Context getContext(); method public final android.view.LayoutInflater.Factory getFactory(); @@ -49561,6 +49562,7 @@ package android.view { method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, @Nullable android.view.ViewGroup, boolean); method protected android.view.View onCreateView(String, android.util.AttributeSet) throws java.lang.ClassNotFoundException; method protected android.view.View onCreateView(android.view.View, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException; + method @Nullable public android.view.View onCreateView(@NonNull android.content.Context, @Nullable android.view.View, @NonNull String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException; method public void setFactory(android.view.LayoutInflater.Factory); method public void setFactory2(android.view.LayoutInflater.Factory2); method public void setFilter(android.view.LayoutInflater.Filter); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 6a290b7fe045..3f18d8b46e2a 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -42,14 +42,16 @@ 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; +import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; import java.util.HashMap; +import java.util.Objects; /** * Instantiates a layout XML file into its corresponding {@link android.view.View} @@ -110,7 +112,12 @@ public abstract class LayoutInflater { // The classloader includes the generated compiled_view.dex file. private ClassLoader mPrecompiledClassLoader; - @UnsupportedAppUsage + /** + * This is not a public API. Two APIs are now available to alleviate the need to access + * this directly: {@link #createView(Context, String, String, AttributeSet)} and + * {@link #onCreateView(Context, View, String, AttributeSet)}. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final Object[] mConstructorArgs = new Object[2]; @UnsupportedAppUsage @@ -721,6 +728,32 @@ public abstract class LayoutInflater { } while (cl != null); return false; } + /** + * Low-level function for instantiating a view by name. This attempts to + * instantiate a view class of the given <var>name</var> found in this + * LayoutInflater's ClassLoader. To use an explicit Context in the View + * constructor, use {@link #createView(Context, String, String, AttributeSet)} instead. + * + * <p> + * There are two things that can happen in an error case: either the + * exception describing the error will be thrown, or a null will be + * returned. You must deal with both possibilities -- the former will happen + * the first time createView() is called for a class of a particular name, + * the latter every time there-after for that class name. + * + * @param name The full name of the class to be instantiated. + * @param attrs The XML attributes supplied for this instance. + * + * @return View The newly instantiated view, or null. + */ + public final View createView(String name, String prefix, AttributeSet attrs) + throws ClassNotFoundException, InflateException { + Context context = (Context) mConstructorArgs[0]; + if (context == null) { + context = mContext; + } + return createView(context, name, prefix, attrs); + } /** * Low-level function for instantiating a view by name. This attempts to @@ -734,13 +767,18 @@ public abstract class LayoutInflater { * the first time createView() is called for a class of a particular name, * the latter every time there-after for that class name. * + * @param viewContext The context used as the context parameter of the View constructor * @param name The full name of the class to be instantiated. * @param attrs The XML attributes supplied for this instance. * * @return View The newly instantiated view, or null. */ - public final View createView(String name, String prefix, AttributeSet attrs) + @Nullable + public final View createView(@NonNull Context viewContext, @NonNull String name, + @Nullable String prefix, @Nullable AttributeSet attrs) throws ClassNotFoundException, InflateException { + Objects.requireNonNull(viewContext); + Objects.requireNonNull(name); Constructor<? extends View> constructor = sConstructorMap.get(name); if (constructor != null && !verifyClassLoader(constructor)) { constructor = null; @@ -787,22 +825,21 @@ public abstract class LayoutInflater { } Object lastContext = mConstructorArgs[0]; - if (mConstructorArgs[0] == null) { - // Fill in the context if not already within inflation. - mConstructorArgs[0] = mContext; - } + mConstructorArgs[0] = viewContext; Object[] args = mConstructorArgs; args[1] = attrs; - final View view = constructor.newInstance(args); - if (view instanceof ViewStub) { - // Use the same context when inflating ViewStub later. - final ViewStub viewStub = (ViewStub) view; - viewStub.setLayoutInflater(cloneInContext((Context) args[0])); + try { + final View view = constructor.newInstance(args); + if (view instanceof ViewStub) { + // Use the same context when inflating ViewStub later. + final ViewStub viewStub = (ViewStub) view; + viewStub.setLayoutInflater(cloneInContext((Context) args[0])); + } + return view; + } finally { + mConstructorArgs[0] = lastContext; } - mConstructorArgs[0] = lastContext; - return view; - } catch (NoSuchMethodException e) { final InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e); @@ -871,6 +908,26 @@ public abstract class LayoutInflater { } /** + * Version of {@link #onCreateView(View, String, AttributeSet)} that also + * takes the inflation context. The default + * implementation simply calls {@link #onCreateView(View, String, AttributeSet)}. + * + * @param viewContext The Context to be used as a constructor parameter for the View + * @param parent The future parent of the returned view. <em>Note that + * this may be null.</em> + * @param name The fully qualified class name of the View to be create. + * @param attrs An AttributeSet of attributes to apply to the View. + * + * @return View The View created. + */ + @Nullable + public View onCreateView(@NonNull Context viewContext, @Nullable View parent, + @NonNull String name, @Nullable AttributeSet attrs) + throws ClassNotFoundException { + return onCreateView(parent, name, attrs); + } + + /** * Convenience method for calling through to the five-arg createViewFromTag * method. This method passes {@code false} for the {@code ignoreThemeAttr} * argument and should be used for everything except {@code >include>} @@ -921,9 +978,9 @@ public abstract class LayoutInflater { mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { - view = onCreateView(parent, name, attrs); + view = onCreateView(context, parent, name, attrs); } else { - view = createView(name, null, attrs); + view = createView(context, name, null, attrs); } } finally { mConstructorArgs[0] = lastContext; |