http://blog.csdn.net/liuxu0703/article/details/70145168

在使用类似textView等View时, 5.0以下的版本中,android会做一个兼容性的处理,生成AppCompatTextView,这样的view的getContext()是TineContextWrapper,如果要强制转为activity或者instanceOfActivity的判断时,不会符合预期的操作

有两种解决办法

  1. 根本的解决办法,采用stackoverflow中的办法,一个工具方法来替换所有的view的getContext(),适用于工程中的这个调用的方式不多,而且修改起来风险不大的地方

  2. 当前问题的解决办法,在5.0以下,看有没有可以禁止这种行为的,是支持的,方式是: 在我们的BaseActivity的onCreate()中,调用getDegate().setCompatVectorFromResourcesEnabled()

可以通过源码查看,在AppCompatActivity的onCreate()中,是安装了一个LayoutInfatorFactory,这里就用于替换的

1) AppCompatDelegateImplV9.onCreateView

 /**     * From {@link android.support.v4.view.LayoutInflaterFactory}     */    @Override    public final View onCreateView(View parent, String name, Context context, AttributeSet attrs) {        // First let the Activity's Factory try and inflate the view        final View view = callActivityOnCreateView(parent, name, context, attrs);        if (view != null) {            return view;        }        // If the Factory didn't handle it, let our createView() method try        return createView(parent, name, context, attrs);    }

2) AppCompatDelegateImplV11.callActivityOnCreateView()

 @Override    View callActivityOnCreateView(View parent, String name, Context context, AttributeSet attrs) {        // On Honeycomb+, Activity's private inflater factory will handle calling its        // onCreateView(...)        return null;    }

发现 callActivityOnCreateView返回null,因而是createView()来控制的

3) AppCompatDelegateImplV9.createView()

 @Override    public View createView(View parent, final String name, @NonNull Context context,            @NonNull AttributeSet attrs) {        if (mAppCompatViewInflater == null) {            mAppCompatViewInflater = new AppCompatViewInflater();        }        boolean inheritContext = false;        if (IS_PRE_LOLLIPOP) {            inheritContext = (attrs instanceof XmlPullParser)                    // If we have a XmlPullParser, we can detect where we are in the layout                    ? ((XmlPullParser) attrs).getDepth() > 1                    // Otherwise we have to use the old heuristic                    : shouldInheritContext((ViewParent) parent);        }        return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,                IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */                true, /* Read read app:theme as a fallback at all times for legacy reasons */                VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */        );    }  

4) mAppCompatViewInflater.createView()的实现

继续翻看代码,能够看到view替换的过程,但是这里我们也看到了有控制的参数,wrapContext为true时,才会做替换,这就是VectorEnabledTintResources.shouldBeUsed()

    public final View createView(View parent, final String name, @NonNull Context context,            @NonNull AttributeSet attrs, boolean inheritContext,            boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {        final Context originalContext = context;        // We can emulate Lollipop's android:theme attribute propagating down the view hierarchy        // by using the parent's context        if (inheritContext && parent != null) {            context = parent.getContext();        }        if (readAndroidTheme || readAppTheme) {            // We then apply the theme on the context, if specified            context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);        }        if (wrapContext) {            context = TintContextWrapper.wrap(context);        }        View view = null;        // We need to 'inject' our tint aware Views in place of the standard framework versions        switch (name) {            case "TextView":                view = new AppCompatTextView(context, attrs);                break;            case "ImageView":                view = new AppCompatImageView(context, attrs);                break;            case "Button":                view = new AppCompatButton(context, attrs);                break;            case "EditText":                view = new AppCompatEditText(context, attrs);                break;            case "Spinner":                view = new AppCompatSpinner(context, attrs);                break;            case "ImageButton":                view = new AppCompatImageButton(context, attrs);                break;            case "CheckBox":                view = new AppCompatCheckBox(context, attrs);                break;            case "RadioButton":                view = new AppCompatRadioButton(context, attrs);                break;            case "CheckedTextView":                view = new AppCompatCheckedTextView(context, attrs);                break;            case "AutoCompleteTextView":                view = new AppCompatAutoCompleteTextView(context, attrs);                break;            case "MultiAutoCompleteTextView":                view = new AppCompatMultiAutoCompleteTextView(context, attrs);                break;            case "RatingBar":                view = new AppCompatRatingBar(context, attrs);                break;            case "SeekBar":                view = new AppCompatSeekBar(context, attrs);                break;        }        if (view == null && originalContext != context) {            // If the original context does not equal our themed context, then we need to manually            // inflate it using the name so that android:theme takes effect.            view = createViewFromTag(context, name, attrs);        }        if (view != null) {            // If we have created a view, check it's android:onClick            checkOnClickListener(view, attrs);        }        return view;    }

5) VectorEnabledTintResources.shouldBeUsed()

public static boolean shouldBeUsed() {        return AppCompatDelegate.isCompatVectorFromResourcesEnabled()                && Build.VERSION.SDK_INT <= MAX_SDK_WHERE_REQUIRED;    }继续追踪    AppCompatDelegate.isCompatVectorFromResourcesEnabled()

6) AppCompatDelegate.isCompatVectorFromResourcesEnabled()

在相关的方法中,可以看到,这个是可以控制的

/**     * Sets whether vector drawables on older platforms (< API 21) can be used within     * {@link android.graphics.drawable.DrawableContainer} resources.     *     * 

When enabled, AppCompat can intercept some drawable inflation from the framework, which * enables implicit inflation of vector drawables within * {@link android.graphics.drawable.DrawableContainer} resources. You can then use those * drawables in places such as {@code android:src} on {@link android.widget.ImageView}, * or {@code android:drawableLeft} on {@link android.widget.TextView}. Example usage:

* *
     * <selector xmlns:android="...">     *     <item android:state_checked="true"     *           android:drawable="@drawable/vector_checked_icon" />     *     <item android:drawable="@drawable/vector_icon" />     * </selector>     *     * <TextView     *         ...     *         android:drawableLeft="@drawable/vector_state_list_icon" />     * 
* *

This feature defaults to disabled, since enabling it can cause issues with memory usage, * and problems updating {@link Configuration} instances. If you update the configuration * manually, then you probably do not want to enable this. You have been warned.

* *

Even with this disabled, you can still use vector resources through * {@link android.support.v7.widget.AppCompatImageView#setImageResource(int)} and it's * {@code app:srcCompat} attribute. They can also be used in anything which AppCompat inflates * for you, such as menu resources.

* *

Please note: this only takes effect in Activities created after this call.

*/ public static void setCompatVectorFromResourcesEnabled(boolean enabled) { sCompatVectorFromResourcesEnabled = enabled; } /** * Returns whether vector drawables on older platforms (< API 21) can be accessed from within * resources. * * @see #setCompatVectorFromResourcesEnabled(boolean) */ public static boolean isCompatVectorFromResourcesEnabled() { return sCompatVectorFromResourcesEnabled; }

找到了设置的方法,就是在BaseActivity中super.oncreate()后,调用getDegate(). setCompatVectorFromResourcesEnabled(false), 注意这个方法的副作用,那就是在5.0以前的系统中,禁用了vector

更多相关文章

  1. H5 调用android原生相机代码分析
  2. android的Fragment解析(一行代码引发的思考)
  3. Android单例关闭应用程序
  4. android的两种启动service方式及混合方式
  5. Android(安卓)MediaScannerService源码分析
  6. RxJava RxAndroid(安卓)在android中最重要的应用(一)
  7. Android学习七---Hello OpenCV samples
  8. Android(安卓)Suspend
  9. Android(安卓)Studio使用来自控制台的模拟器,/dev/kvm device:

随机推荐

  1. Android Studio——理解Intent和Intent F
  2. Android 开发中遇到的 bug(5)
  3. android实现标题栏、状态栏图标文字颜色
  4. Android Studio--报错日记
  5. [置顶] 我的Android进阶之旅------>Andro
  6. Android DEX 方法超过64K限制
  7. android--创建快捷方式和判断是否已经创
  8. Android ApiDemos示例解析(137):Views->L
  9. 高煥堂的四本Android开发新書(簡體完整版
  10. Android的内存优化相关记录