Files
timi-fx/src/main/java/com/imyeyu/fx/task/RunAsync.java
2026-01-13 17:50:44 +08:00

299 lines
7.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.imyeyu.fx.task;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import com.imyeyu.java.bean.Callback;
import com.imyeyu.java.bean.CallbackArg;
import com.imyeyu.java.bean.CallbackReturn;
/**
* 异步线程执行,常用的构建异步线程任务
*
* <pre>
* // 快速构造
* RunAsync.run(() -> {}); // 快速异步执行 {@link #run(Callback)}
* RunAsync.run(() -> {}, () -> {}); // 快速异步回调 {@link #run(Callback, Callback)}
* RunAsync.run(() -> 100, v -> {}); // 快速异步返回 {@link #callbackReturn(CallbackReturn, CallbackArg)}
* RunAsync.later(() -> {}, 1000); // 延时一秒执行 {@link #later(Callback, long)}
*
* // 标准构造
* new RunAsync&lt;T&gt;() {
*
* &#064;Override
* protected T call() throws Exception {
*
* // 这里不是 FX 线程,可以执行一些长时间的事情
*
* update(new T()); // 主动更新数据
* progress(.6); // 更新进度
* return new T(); // 返回更新数据
* }
*
* &#064;Override
* protected void onUpdate(T t) {
* // 数据更新事件,属于 FX 线程,视 UI 线程状态回调
* }
*
* &#064;Override
* protected void onUpdateProgress(double progress) {
* // 更新进度事件,属于 FX 线程,视 UI 线程状态回调
* }
*
* &#064;Override
* protected void onFinish() {
* // 线程执行完成,属于 FX 线程
* }
*
* &#064;Override
* protected void onException(Throwable e) {
* // 线程异常,属于 FX 线程
* }
* }.start(); &lt;-- 千万别忘了启动任务
* </pre>
*
* @author 夜雨
* @since 2021-02-13 12:56
* @param <T> 数据处理返回类型
*/
public abstract class RunAsync<T> extends Service<T> {
/** 任务对象 */
protected PublicTask<T> task;
/** 最近一次更新数据 */
protected T lastT;
protected boolean isInterrupted = false;
@Override
protected Task<T> createTask() {
task = new PublicTask<>() {
protected T call() throws Exception {
return RunAsync.this.call();
}
};
task.setOnScheduled(e -> isInterrupted = false);
task.setOnSucceeded(e -> {
onFinish();
onFinish(lastT);
onFinally();
isInterrupted = false;
});
task.setOnFailed(e -> {
onFinally();
isInterrupted = false;
});
task.valueProperty().addListener((obs, o, t) -> {
lastT = t;
onUpdate(t);
});
task.messageProperty().addListener((obs, o, msg) -> onMessage(msg));
task.progressProperty().addListener((obs, o, p) -> onProgress(p.doubleValue()));
task.exceptionProperty().addListener((obs, o, e) -> onException(e));
return task;
}
/**
* 执行事件(非 FX 线程)
*
* @return 处理结果
* @throws Exception 处理异常
*/
protected abstract T call() throws Exception;
/**
* 主动更新数据,通常是非 FX 线程的 call 里触发,{@link #onUpdate(T)} 里视 UI 线程状态回调
*
* @param t 更新值
*/
protected void update(T t) {
lastT = t;
task.updateValue(t);
}
/**
* 主动更新进度,非 FX 线程的 call 里触发,{@link #onProgress(double)} 里视 UI 线程状态回调
*
* @param progress 进度值
*/
protected void progress(double progress) {
task.updateProgress(progress, 1);
}
/**
* 更新消息,非 FX 线程的 call 里触发,{@link #onMessage(String)} 里视 UI 线程状态回调
*
* @param msg 消息
*/
protected void message(String msg) {
task.updateMessage(msg);
}
/**
* 数据更新事件,{@link #update(T)} 或 {@link #call()} 返回参数触发,属于 FX 线程
*
* @param t 更新数据
*/
protected void onUpdate(T t) {
// 子类实现
}
/**
* 更新进度事件,{@link #progress(double)} 触发,属于 FX 线程
*
* @param progress 进度值
*/
protected void onProgress(double progress) {
// 子类实现
}
/**
* 更新消息
*
* @param msg 消息
*/
protected void onMessage(String msg) {
// 子类实现
}
/** 完成事件FX 线程,只要线程结束就会调用) */
protected void onFinish() {
// 子类实现
}
/**
* 完成事件FX 线程,只要线程结束就会调用,参数为 {@link #update(T)} 或 {@link #call()} 最后一次更新值)
*
* @param t 执行事件返回值
*/
protected void onFinish(T t) {
// 子类实现
}
/**
* 发生异常FX 线程)
*
* @param e 异常
*/
protected void onException(Throwable e) {
e.printStackTrace();
}
/** 线程完成监听,无论正常完成还是出现异常,都会触发此方法 */
protected void onFinally() {
// 子类实现
}
/** 中断任务 */
public void interrupt() {
isInterrupted = true;
cancel();
}
// ---------- 静态构造 ----------
/**
* 快速构造稍后执行,触发事件属于 FX 线程
*
* @param callback 异步事件
* @param delay 延时时间(毫秒)
*/
public static void later(Callback callback, long delay) {
run(() -> {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, callback);
}
/**
* 快速构造异步任务
*
* @param callback 异步回调
*/
public static void run(Callback callback) {
run(callback, null, null);
}
/**
* 快速构造异步任务
*
* @param asyncCallback 异步回调
* @param finishCallback 异步完成回调
*/
public static void run(Callback asyncCallback, Callback finishCallback) {
run(asyncCallback, finishCallback, null);
}
/**
* 快速构造异步任务
*
* @param asyncCallback 异步回调
* @param exceptionCallback 异常回调
*/
public static void run(Callback asyncCallback, CallbackArg<Throwable> exceptionCallback) {
run(asyncCallback, null, exceptionCallback);
}
/**
* 快速构造异步任务(私有为了可读性,既然主要事件都用上了那应该使用 new {@link RunAsync}() 来保持可读性)
*
* @param asyncCallback 异步回调
* @param finishCallback 异步完成回调
* @param exceptionCallback 异常回调
*/
private static void run(Callback asyncCallback, Callback finishCallback, CallbackArg<Throwable> exceptionCallback) {
new RunAsync<Void>() {
@Override
protected Void call() {
asyncCallback.handler();
return null;
}
@Override
protected void onFinish() {
try {
if (finishCallback != null) {
finishCallback.handler();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onException(Throwable e) {
if (exceptionCallback != null) {
exceptionCallback.handler(e);
}
}
}.start();
}
/**
* 快速构造异步任务
*
* @param asyncCallback 异步回调
* @param finishCallback 异步完成回调
* @param <T> 回调数据类型
*/
public static <T> void callbackReturn(CallbackReturn<T> asyncCallback, CallbackArg<T> finishCallback) {
new RunAsync<T>() {
@Override
protected T call() {
return asyncCallback.handler();
}
@Override
protected void onFinish(T t) {
finishCallback.handler(t);
}
}.start();
}
}