测试中使用Looper调度器时Observable.create未执行的问题排查
我来帮你分析下这个问题,你遇到的Observable.create里的代码块完全没执行的情况,大概率和Looper调度器的线程状态或者测试逻辑有关,咱们一步步来拆解:
首先先明确你的问题代码:
待测试代码:
public Observable<Void> prepare() { return Observable.<Void>create(subscriber -> { // 此处代码从未执行 subscriber.onCompleted(); }).subscribeOn(scheduler); }
其中scheduler是继承自HandlerThread的Looper调度器,测试使用TestSubscriber。
核心原因排查
1. Looper调度器的线程未正确启动
subscribeOn(scheduler)会把Observable.create中的逻辑包装成任务,提交到调度器对应的线程消息队列中。但如果你的Looper调度器(也就是那个继承HandlerThread的类)没有调用start()方法启动线程,那么线程的Looper根本不会运行,消息队列里的任务永远不会被执行。
2. 测试代码未等待任务执行完成
在单元测试场景下,如果你的TestSubscriber没有等待Observable执行完成,测试方法可能在Looper线程的任务还没来得及执行时就已经结束了,看起来就像代码块没跑过一样。
针对性解决方案
方案一:确保Looper调度器的HandlerThread已启动
检查你的Looper调度器实现,必须调用start()来启动线程,并且初始化Handler时要拿到有效的Looper。示例实现如下:
public class LooperScheduler extends HandlerThread implements Scheduler { private Handler handler; public LooperScheduler(String threadName) { super(threadName); // 必须启动线程,否则Looper不会工作 start(); // 等待Looper初始化完成(HandlerThread的getLooper会阻塞直到Looper创建) handler = new Handler(getLooper()); } @Override public Worker createWorker() { return new Worker() { @Override public Subscription schedule(Action0 action) { handler.post(() -> action.call()); return Subscriptions.empty(); } @Override public void unsubscribe() { handler.removeCallbacksAndMessages(null); } @Override public boolean isUnsubscribed() { return false; } }; } }
重点提醒:一定要调用start(),这是很多人容易忽略的点!
方案二:完善测试代码,等待Observable执行完成
修改你的测试代码,添加等待终端事件的逻辑,确保测试不会提前结束:
@Test public void prepare() throws Exception { TestSubscriber<Void> testSubscriber = new TestSubscriber<>(); // 订阅Observable prepare().subscribe(testSubscriber); // 等待Observable完成,设置合理的超时时间 testSubscriber.awaitTerminalEvent(5, TimeUnit.SECONDS); // 验证结果:确认onCompleted被调用,且无错误 testSubscriber.assertCompleted(); testSubscriber.assertNoErrors(); }
如果没有awaitTerminalEvent这一步,测试方法会直接走完,而Looper线程的任务还在排队,自然看不到代码块执行的痕迹。
方案三:验证调度器实例有效性
最后可以在prepare()方法里加个简单的日志,确认scheduler不是null,并且对应的线程是活跃状态:
public Observable<Void> prepare() { // 打印调度器线程状态,排查问题 Log.d("SchedulerCheck", "Scheduler thread alive: " + scheduler.isAlive()); return Observable.<Void>create(subscriber -> { // 此处代码从未执行 subscriber.onCompleted(); }).subscribeOn(scheduler); }
按照这几个步骤排查和修复,应该就能解决代码块未执行的问题了。
内容的提问来源于stack exchange,提问作者Itay k

