范型&&诡异异常

androidL 版本的异常:
1、jobservice 异常,idle 错误
2、data分区 没有空间 profile.xml 写入中断,循环解析,无法开机
3、keyguard keyguardscrim 引起的黑屏问题

Looper 中是使用一个ThreadLocal 来存储 当前线程的 looper的,
static final ThreadLocal sThreadLocal = new ThreadLocal();
在prepare 方法中,对此 ThreadLocal 方法赋值:

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}

在myLooper 中会取出 此 ThreadLocal 中的 looper 对象:

public static Looper myLooper() {    
    return sThreadLocal.get();
}

但是突然有一天见到一个诡异的异常:

java.lang.ClassCastException: java.lang.StringBuilder cannot be cast to android.os.Looper
    at android.os.Looper.myLooper(Looper.java:249)
    at android.database.sqlite.SQLiteDatabase.isMainThread(SQLiteDatabase.java:404)
    at android.database.sqlite.SQLiteDatabase.getThreadDefaultConnectionFlags(SQLiteDatabase.java:395)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:59)
    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1024)
    at com.android.providers.contacts.LegacyApiSupport.<init>(LegacyApiSupport.java:532)
    at com.android.providers.contacts.ContactsProvider2.initForDefaultLocale(ContactsProvider2.java:1930)
    at com.android.providers.contacts.ContactsProvider2.performBackgroundTask(ContactsProvider2.java:2055)
    at com.android.providers.contacts.ContactsProvider2$1.handleMessage(ContactsProvider2.java:12238)
    at android.os.Handler.dispatchMessage(Handler.java:111)
    at android.os.Looper.loop(Looper.java:207)
    at android.os.HandlerThread.run(HandlerThread.java:61)

ThreadLocal 里面被存入了一个 StringBuilder ,然后在myLooper 中取出时发生了异常,先不说是谁能干出这档子事,先探究一下他是怎么存进去的:
范型是 存在于代码编译期,在生成字节码时,编译器会将范型去除,做类型擦除,
所以在ThreadLocal 中存入一个StringBuilder 只有可能在运行时完成,我所知道,能在运行时完成这件事的只有 反射了:

Field field = Looper.class.getDeclaredField("sThreadLocal");
field.setAccessible(true);
ThreadLocal sThreadLocal = ThreadLocal.class.cast(field.get(null));
Method method = ThreadLocal.class.getMethod("set", Object.class);
method.invoke(sThreadLocal, new StringBuilder());

如果使用这种方法,一般也不需要处理,可是本次发生的问题,是属于系统级apk的,并且系统源码里面没有找到此类的调用,哎,很是 奇怪啊,最后迫于无奈,在ThreadLocal 类的 set 方法里面添加了一下类型判断:

public void set(T value) {
    T oldValue = get();
    if(oldValue != null && value != null && !((oldValue.getClass()).equals(value.getClass()))){
        throw new RuntimeException();
    }
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);
    if (values == null) {
       values = initializeValues(currentThread);
    }
    values.put(this, value);
}

以此来规避,反射调用此方法,产生的异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值