鸿蒙 2.0 beta 版发布了,小伙伴又双叕有新的学习目标了。(掀桌子!有完没完了!!) 既然是用 Java 编程,怎么能少了 RxJava 这尊大神呢!
目标:主线程任务调度器
说起 RxJava,便捷的线程调度是其非常重要的特性,在 Android 系统中,RxAndroid 库已经提供了成熟的主线程调度器,本文的目标就是参考其思路实现鸿蒙系统下的主线程调度器。
经在线设备测试,RxJava3 可以正常运行在当前鸿蒙系统中,且鸿蒙提供了和 Android 类似的 Handler Message 多线程通信框架,那就可以通过该框架实现 HarmonyScheduler(线程调度器)了。
实现方案
参考 RxAndroid 思路,异步任务调度到主线程的核心逻辑就是包装待执行的 Runnable,然后将其通过 EventHandler 发送到主线程中执行。
核心的调度和结束调度的方法。
private static final class HandlerWorker extends Worker {
private final RunnableObjHandler handler;
private final boolean async;
private volatile boolean disposed;
private static AtomicLong count = new AtomicLong();
// 每次新建一个 Worker 都定义 param 参数,用于移除该 Worker.dispose() 方法中移除所有该类创建的任务
private final long paramForDispose;
HandlerWorker(RunnableObjHandler handler, boolean async) {
this.handler = handler;
this.async = async;
paramForDispose = count.incrementAndGet();
}
@Override
// @SuppressLint("NewApi") // Async will only be true when the API is available to call.
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
if (run == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
if (disposed) {
return Disposable.disposed();
}
run = RxJavaPlugins.onSchedule(run);
// 对 runnable 参数进行包装,增加了 dispose() 方法
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
// 这块注释是 RxAndroid 的实现,放这这里作为参考
// Message message = Message.obtain(handler, scheduled);
// message.obj = this; // Used as token for batch disposal of this worker's runnables.
//
// if (async) {
// message.setAsynchronous(true);
// }
//
// handler.sendMessageDelayed(message, unit.toMillis(delay));
//
// // Re-check disposed state for removing in case we were racing a call to dispose().
// if (disposed) {
// handler.removeCallbacks(scheduled);
// return Disposable.disposed();
// }
// 可以看到核心逻辑就是将传入 Runnable 参数进行包装,然后通过 handler 发到主线程
// 比较麻烦的是 dispose 处理,因为目前鸿蒙的 InnerEvent 实例无法通过 Runnable 参数获取,所以各种 dispose 逻辑就无法按 Android 的那套实现。
// 我的方案是将 Runnable 传入 InnerEvent.object,然后自定义 Handler,处理 InnerEvent 时强转 object 参数,然后直接调用 run 方法
// paramForDispose 是 long 类型的标志位(HandlerWorker 实例化定义的固定值),用于标志该 Worker 所调度的所有 Runnable,设置到 param 参数,
// 这样 Dispose 时,可根据 object 移除单任务,也可通过 param 移除该 Worker 创建的所以任务
InnerEvent message = InnerEvent.get(handler.getInnerEventId());
message.object = scheduled;
message.param = paramForDispose;
handler.sendEvent(message, unit.toMillis(delay));
// Re-check disposed state for removing in case we were racing a call to dispose().
if (disposed) {
// 通过 object 参数去移除当前构建的 ScheduledRunnable 的 InnerEvent,该方法必须指定 InnerEventId,所以在自定义 Handler 中提供
handler.removeEvent(handler.getInnerEventId(), scheduled);
return Disposable.disposed();
}
return scheduled;
}
@Override
public void dispose() {
disposed = true;
// handler.removeCallbacksAndMessages(this /* token */);
// 通过 param 参数移除该 Worker 已调度的所有 InnerEvent
handler.removeEvent(handler.getInnerEventId(), paramForDispose);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
ScheduledRunnable 包装类
private static final class ScheduledRunnable implements Runnable, Disposable {
private final RunnableObjHandler handler;
private final Runnable delegate;
private volatile boolean disposed; // Tracked solely for isDisposed().
ScheduledRunnable(RunnableObjHandler handler, Runnable delegate) {
this.handler = handler;
this.delegate = delegate;
}
@Override
public void run() {
try {
delegate.run();
} catch (Throwable t) {
RxJavaPlugins.onError(t);
}
}
@Override
public void dispose() {
// handler.removeCallbacks(this);
handler.removeEvent(handler.getInnerEventId(), this);
disposed = true;
}
@Override
public boolean isDisposed() {
return disposed;
}
}
自定义 Handler
static class RunnableObjHandler extends EventHandler {
private static AtomicInteger count = new AtomicInteger();
// 每个 Handler 实例提供固定的 innerEventId
private final int innerEventId;
public RunnableObjHandler(EventRunner runner) throws IllegalArgumentException {
super(runner);
innerEventId = HandlerScheduler.class.hashCode() + count.incrementAndGet();
}
private int getInnerEventId() {
return innerEventId;
}
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event.eventId != innerEventId) return;
Object obj = event.object;
if (obj instanceof Runnable) {
((Runnable)obj).run();
}
}
}
这样,写鸿蒙 app 时,也可以“流”动起来了。
完整项目地址,如果对你有帮助的话请点个赞,点个 star,谢谢