• view的context一定是Activity吗


    最近在使用glide加载图片的时候出现“Caused by: java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity”,但明明在使用glide之前已经进行了Activity是否destroy的判断,为什么还会发生这个crash呢?注意到Android版本为4.4.2,对应crash中glide使用的context为view.getContext(),所以是不是因为view.getContext()不是Activity类型,所以没有走到判断逻辑,debug发现此时的view.getContext()为TintContextWrapper类型,这是为什么呢?

    源码分析

    我的view继承android.support.v7.widget包下的AppCompatImageView,查看AppCompatImageView源码如下:
    在这里插入图片描述
    可以看到在AppcompatImageView中的super方法中对于原本传入的context进行了封装也就是TintContextWrapper.wrap(context),查看TintContextWrapper.wrap(context)方法源码如下:

    public class TintContextWrapper extends ContextWrapper {
        private static final Object CACHE_LOCK = new Object();
        private static ArrayList<WeakReference<TintContextWrapper>> sCache;
        private final Resources mResources;
        private final Theme mTheme;
    
        public static Context wrap(@NonNull Context context) {
            if (shouldWrap(context)) {
                synchronized(CACHE_LOCK) {
                    if (sCache == null) {
                        sCache = new ArrayList();
                    } else {
                        int i;
                        WeakReference ref;
                        for(i = sCache.size() - 1; i >= 0; --i) {
                            ref = (WeakReference)sCache.get(i);
                            if (ref == null || ref.get() == null) {
                                sCache.remove(i);
                            }
                        }
    
                        for(i = sCache.size() - 1; i >= 0; --i) {
                            ref = (WeakReference)sCache.get(i);
                            TintContextWrapper wrapper = ref != null ? (TintContextWrapper)ref.get() : null;
                            // 将context赋值给了baseContext
                            if (wrapper != null && wrapper.getBaseContext() == context) {
                                return wrapper;
                            }
                        }
                    }
    
                    TintContextWrapper wrapper = new TintContextWrapper(context);
                    sCache.add(new WeakReference(wrapper));
                    return wrapper;
                }
            } else {
                return context;
            }
        }
        // 判断是否封装context
        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;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    可以看出来TintContextWrapper继承ContextWrapper。在wrap方法中根据shouldWrap(context)进行判断。
    (1)shouldWrap(context)为false,直接返回外部传入的context,未进行封装。
    (2)shouldWrap(context)为true,将外部传入的context赋值给TintContextWrapper的baseContext,封装成TintContextWrapper。
    查看
    shouldWrap
    方法,VERSION.SDK_INT < 21(Android5.0)时会返回true,封装context。

    总结:对于view的context,android5.0以下,使用v7包下的view,对应的view的context为TintContextWrapper类型,其余时为activity类型。

    view的context获取Activity

    从上面得知,view的context不一定是Activity,那我们怎么从view的context得到对应的Activity呢?
    方法如下:

    private fun getActivityFromView(viewContext: Context): Activity? {
        var context = viewContext
        while (context is ContextWrapper) {
            if (context is Activity) {
                return context
            }
            context = context.baseContext
        }
        return null
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    参考

    https://blog.csdn.net/yyanjun/article/details/79896677
    https://www.jianshu.com/p/448c578a252b

  • 相关阅读:
    饼图(内环饼图)
    git am冲突解决办法
    软考备考-程序员-备考笔记
    测试面试题集锦(四)| Linux 与 Python 编程篇(附答案)
    以深圳为例Python一键生成核酸检测日历
    实现基于 Jenkins 的多服务器打包方案
    Spring Cloud 简介
    Vue前端框架的使用
    从0开始学汇编第二天:寄存器(CPU工作原理)
    ubuntu 18 更新git版本到 2.80.1
  • 原文地址:https://blog.csdn.net/liuwei187/article/details/127922128