子线程创建方法1:
ScheduledExecutorService schedulePool = Executors.newScheduledThreadPool(2);
schedulePool.schedule(new Runnable() {
@Override
public void run() {
dorequest();
}
}, 2, TimeUnit.SECONDS);
子线程创建方法2:
new Thread(new Runnable() {
@Override
public void run() {
dorequest();
}
}).start();
dorequest 代码:
Log.e("aaaaa", "dorequest");
Request request = new Request.Builder() .url("http://www.baidu.com").build();
okhttp3.OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
// 导致请求停止的原因
Handler h = new Handler();
clientBuilder.build().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("aaaaa", "onFailure");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("aaaaa", "onResponse");
}
});
创建方法1 的运行结果:
方法运行中断,没有结果 。中断直接连网络请求都没有发出
创建方法2的运行结果:
直接crash,没有触发Looper.prepare()
问题的原因是在子线程中直接 new 了 handler 。如果不带 handler 时则正常。
由此有两种解决方案:
方案一:补全 looper
private void dorequest(){
Log.e("aaaaa", "dorequest");
Request request = new Request.Builder() .url("http://www.baidu.com").build();
okhttp3.OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
// 在new之前触发 prepare
Looper.prepare();
Handler h = new Handler();
clientBuilder.build().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e("aaaaa", "onFailure");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.e("aaaaa", "onResponse");
}
});
// 在完成时要 loop
Looper.loop();
}
方案二:指定主线程中创建 handler
// 修改这一句即可
Handler h = new Handler(Looper.getMainLooper());
这次写这个不是因为 looper,而是因为 schedulePool 在没有处理 looper 时居然不报错,而是直接return了,正好碰到这个问题,发现 okhttp 没有实际请求,查半天才发现是这个漏处理了,所以记录一下。
ScheduledExecutorService
特别需要注意,一旦SES执行的逻辑中抛出异常,那么调度会自动停止,并且不会有任何提示信息。在其scheduleWithFixedDelay()和scheduleAtFixedRate()方法的JavaDoc中,都有这样的描述:
ScheduledExecutorService (Java Platform SE 8 )
If any execution of the task encounters an exception, subsequent executions are suppressed.
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
同时,通过线程工厂ThreadFactory设置异常处理器UncaughtExceptionHandler是没有作用的,也就是说SES遇到异常时根本不会调用uncaughtException()方法。
具体错误捕获,请参见:
ScheduledExecutorService异常处理的正确姿势-CSDN博客
Java中的定时任务-ScheduledExecutorService的坑 | yilan