今天我们来说一个小bug,如题所示
我们先来看看这个bug是如何出现的:
Activity activity = (Activity) view.getContext();
代码就这么简单,按理来说,一个view出现在某个activity中,那么我们获取它的context强转为activity应该没什么毛病才对啊,为什么还会报如题的错误呢?
首先,我们来看看出现这个bug的条件:
1)这个bug基本只会出现在Android5.0以下,5.0以上并不存在这个bug
2)上面这个view使用或继承的是AppCompat系列的View,比如:AppCompatTextView、AppCompatImageView、AppCompatButton等
3)如果你当前activity继承的是v7兼容包里的AppCompatActivity,那么,就算你使用普通的TextView或Button,也会出现同样的bug,因为activity继承自AppCompatActivity后,你的TextView、Button会自动转换为AppCompatTextView、AppCompatButton,这样一来就同第2点了
接下来,我们来看看报这个错的原因:
我们先看看AppCompatButton的构造函数,如下:
public AppCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(TintContextWrapper.wrap(context), attrs, defStyleAttr);
......
}
context 被用 TintContextWrapper 包了一层,如果你去打log的话,你会发现此时getContext获取的类型是TintContextWrapper,所以在Android5.0以下进行强转就会报错,而为什么在Android5.0以下才会报错呢?TintContextWrapper中的关键代码如下:
private static boolean shouldWrap(@NonNull Context context) {
if (!(context instanceof TintContextWrapper) && !(context.getResources() instanceof TintResources) && !(context.getResources() instanceof VectorEnabledTintResources)) {
return VERSION.SDK_INT < 21 || VectorEnabledTintResources.shouldBeUsed();
} else {
return false;
}
}
好啦,出现bug的条件及原因已经说清楚了,那么,我们来看看解决的方案:
1)最无赖(无奈)的做法,你直接把你兼容的最小版本minSdkVersion设为21,一刀切了,够狠的
2)如果你的项目中没有使用AppCompat系列的View,那么只要你的BaseActivity别继承AppCompatActivity就行了,你可以选择继承FragmentActivity等
3)如果你要使用AppCompat系列的View,那么也不难,既然知道了原因是因为被TintContextWrapper包装了,那么我们只需拆开包装即可:
public static Activity getActivityFromView(View view) {
if (null != view) {
Context context = view.getContext();
while (context instanceof ContextWrapper) {
if (context instanceof Activity) {
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
}
return null;
}
参考链接:https://blog.csdn.net/sted_zxz/article/details/79380231
网友评论