Looper,flutterui套件
账号是如何被挤?又是如何跳转到登录页面的?终于,凶手露出了水面,凶手就是Looper,原来妹子是通过OkHttp的拦截器来监听账号被挤,并通过Looper来弹出一个Toast提示,并且执行页面跳转逻辑,如下:public class TokenInterceptor implements Interceptor {private Context context;//省略部分代码@Overridep
账号是如何被挤?又是如何跳转到登录页面的?
终于,凶手露出了水面,凶手就是Looper,原来妹子是通过OkHttp的拦截器来监听账号被挤,并通过Looper来弹出一个Toast提示,并且执行页面跳转逻辑,如下:
public class TokenInterceptor implements Interceptor {
private Context context;
//省略部分代码
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response originalResponse = chain.proceed(request);
String code = originalResponse.header(“code”);
if ("-1".equals(code)) { //账号被挤
Looper.prepare();
Toast.makeText(context, “你的账号在其它设备上登录”, Toast.LENGTH_LONG).show();
context.startActivity(new Intent(context, LoginActivity.class));
Looper.loop();
}
return originalResponse;
}
}
也许你会问,这确定有问题?通过Looper在子线程弹出一个Toast,这不是很正常的一件事?经常这么干,从来没出现任何问题,为啥到你这就出问题?
我让妹子把Looper及Toast代码注释掉,if语句里面只保留一行startActivity,妹子试后开心的跟我说,好了,没问题了,这怎么解释?
Looper一脸委屈的说道:你说我是凶手,我就是凶手了,证据呢?
ok,我们就来寻找证据,我们知道,Looper.loop()方法内部,会开启一个死循环,如下:
public static void loop() {
//省略部分代码
for (;😉 {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//省略部分代码
}
//省略部分代码
}
可以看到,queue.next()这行代码官方注释了,有可能会被堵塞,什么时候会堵塞?没有消息的时候,可见,调用Looper.loop()方法所在的线程会进入死循环。
那这个和我们的案件有什么关系呢?
这就要来说说RxJava的线程池了,上面TokenInterceptor回调所在的线程是RxJava的IO线程,而RxJava的IO线程池的配置,却仅允许一条核心线程执行任务,当任务在执行,其它任务过来时,必须等待至上一个任务结束。
在IoScheduler类中可以找到静态内部类ThreadWorker,ThreadWorker继承至NewThreadWorker,在该类中,我们可以找到线程池对象,如下:
public class NewThreadWorker extends Scheduler.Worker implements Disposable {
private final ScheduledExecutorService executor;
//省略部分代码
public NewThreadWorker(ThreadFactory threadFactory) {
//这里创建了线程池
executor = SchedulerPoolFactory.create(threadFactory);
}
//省略部分代码
}
SchedulerPoolFactory.create方法点进去看看
public static ScheduledExecutorService create(ThreadFactory factory) {
final ScheduledExecutorService exec = Executors.newScheduledThreadPool(1, factory); //核心线程数量为1
//省略部分代码
return exec;
}
可以看到,这里传了个1,就是核心线程的数量,继续往下看,最终找到了创建线程池对象代码,如下:
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
这里简单解读一下,该线程池核心线程数量为1,非核心线程数量无上限,非核心线程闲置时间超过10毫秒便会被回收,并使用了延迟队列。
注意注意,前方高能预警
用简单的话来说,该线程池,同一时间,仅会执行一个任务,也就是串行,这也就解释Looper与本案的关系,因为Looper.loop()所在线程进入死循环,该线程所在线程池收到其它任务时,便必须得等待至上一个任务执行完毕,然而上一个任务在死循环,所以下一个任务永远得不到执行,这也就是为什么请求代码执行了,请求却没发出去原因。
到这,估计很多人会有疑问
RxJava的Io线程池,是串行执行的,那么它又是如何做到并行的呢?难道以前写的并行代码,其实都是串行实现的?
线程池已经有任务在执行了,为啥还会拿到该线程池执行新的任务呢?
RxJava为啥不使用OkHttp内部的线程池配置,只要有任务来,都开启非核心线程去执行?
ok,接下来一一解答
首先,第一个,RxJava如何根据目前的Io线程池,做到并行任务?
其实很简单,在IoScheduler的静态内部类CachedWorkerPool中,维护了一个线程池队列,每次收到新任务,都会从队列里面取出一个线程池去执行任务,如果没有,则创建一个新的线程池,如下:
static final class CachedWorkerPool implements Runnable {
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。
这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司21年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
由于篇幅有限,这里以图片的形式给大家展示一小部分。

详细整理在GitHub可以见;
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
er/Android%E5%BC%80%E5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)**
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
更多推荐



所有评论(0)