En référence à RxAndroid, j'ai créé un Scheduler
compatible avec RxJava 2.x pour le thread d'interface utilisateur de Swing.
** Pas Swift **. Merci pour votre soutien.
doOnSubscribe
Est le but de cet article. Il semble que personne n'utilise RxSwing. De plus, aucune connaissance de Swing n'est requise.
RxSwing existe en tant que l'un des projets ReactiveX. https://github.com/ReactiveX/RxSwing
Mais contrairement à RxAndroid et RxCocoa,
Non inclus dans ReactiveX pour les plates-formes et les frameworks
.
http://reactivex.io/languages.html
De plus, il n'y a pas encore de support pour RxJava 1.x.
Il existe une demande d'extraction qui prend en charge RxJava 2.x, mais il semble qu'elle a été laissée sans surveillance. https://github.com/ReactiveX/RxSwing/pull/63
Le projet officiel RxSwing2 a également un cadre, mais cette Pull Request est également négligée. https://github.com/ReactiveX/RxSwing2/pull/1
Il y a aussi la question de savoir combien de temps Swing restera, Peut-être que RxJava 3 sortira avant la fin de Swing. (Je dis quelque chose d'approprié.) Je pense qu'il est difficile d'éteindre et de maintenir RxSwing2 compatible avec RxJava2 dans un cycle aussi précoce, donc Est-ce un endroit où la sortie et les critiques sont hésitantes?
En attendant, s'il y a un support minimal, ce serait le contrôle des threads pour exécuter l'interface utilisateur. * 1
Comme le fil d'Android UI Swing dispose également d'un fil de discussion (EDT) pour exécuter l'interface utilisateur. (L'événement ici est un événement lié à l'interface utilisateur.) Cependant, bien que le fil d'interface utilisateur soit le fil principal sur Android, * 2 L'EDT de Swing est un thread distinct du thread principal Java.
Dans la série Rx, le contrôle des threads est laissé à Scheduler
.
Pour que vous puissiez écrire du code avec presque la même API dans la série Rx
La gestion des threads dans chaque plate-forme et langue est confinée dans le Scheduler
.
Looper et Handler pour Android, GCD pour iOS,
Il semble que chacun soit utilisé.
https://github.com/ReactiveX/RxAndroid/blob/2.x/rxandroid/src/main/java/io/reactivex/android/schedulers/AndroidSchedulers.java
https://github.com/ReactiveX/RxSwift/blob/master/RxSwift/Schedulers/MainScheduler.swift
Heureusement, dans le cas de Swing, il n'est pas nécessaire de traiter directement avec Thread
ou ʻExecutor` de Java.
Les classes «Timer» et «SwingUtilities» sont utilisées.
https://github.com/ReactiveX/RxSwing/blob/0.x/src/main/java/rx/schedulers/SwingScheduler.java
Scheduler
dans RxJavapublic abstract Worker createWorker();
Créer un Scheduler
dans RxJava, c'est avant tout implémenter les méthodes suivantes.
public abstract Worker createWorker();
Ce «Woker» doit au moins implémenter les méthodes suivantes et «Jetable».
public abstract Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit);
public interface Disposable {
void dispose();
boolean isDisposed();
}
Et à propos du Runnable
passé à la méthode schedule ()
Il est de la responsabilité du «travailleur» de garantir.
Scheduler
Si vous souhaitez exécuter l'interface utilisateur avec RxJava
Pour RxAndroid, utilisez ʻAndroidSchedulers.mainThread () . Ceci est une instance de
HandlerScheduler`
Celui créé en passant le gestionnaire du thread principal au constructeur est réutilisé.
new HandlerScheduler(new Handler(Looper.getMainLooper()));
AndroidSchedulers.java HandlerScheduler.java
En utilisant la fonction de Handler, le rappel est appelé à l'heure spécifiée et le rappel est supprimé. Extrait ci-dessous, mais si vous ne pouvez pas attendre, regardez le code et dites «Je vois».
Travailleur
Comme mentionné ci-dessus, il y a deux PR dans le référentiel officiel qui prennent en charge RxJava 2.x,
C'est fondamentalement la même chose, donc je ne regarderai que le Scheduler
et Worker
qui sont PR pour RxSwing2.
Il y a peu de différence avec celle de RxJava 1.x. Cependant, il y a une chose à craindre.
Ci-dessous un extrait de la classe RxSwing2 Worker
.
https://github.com/UeliKurmann/RxSwing2/blob/8012ae881aa58cbb829433554489f9b83e6411ea/src/main/java/rx/schedulers/SwingScheduler.java
// Worker of RxSwing2 for RxJava2.x
private final CompositeDisposable innerSubscription = new CompositeDisposable();
@Override
public Disposable schedule(final Runnable action, long delayTime, TimeUnit unit) {
//réduction
//Retourner insideSubscription tel quel
return innerSubscription;
}
@Override
public void dispose() {
innerSubscription.dispose();
}
@Override
public boolean isDisposed() {
return innerSubscription.isDisposed();
}
En d'autres termes, les deux processus suivants sont égaux.
dispose ()
à l'instance Worker
Dispose ()
à l'instance Disposable
retournée par schedule ()
de l'instance Worker
Et cette utilisation n'est pas «Composite jetable»
Je pense que vous devriez utiliser Disposables.empty ()
.
L'utilisation de «CompositeDisposable» peut simplement être un vestige de l'ancien RxSwing.
Travailleur
Pour ceux qui ont oublié RxJava 1.x, voici les classes correspondantes.
Version | classe | Méthode |
---|---|---|
RxJava1.x | Subscription | unsubscribe() |
RxJava2.x | Disposable | dispose() |
Ci-dessous, un extrait de la classe Worker
de RxSwing1.
https://github.com/ReactiveX/RxSwing/blob/281ddb9500bea4ce8b44fccde907963712647ab4/src/main/java/rx/schedulers/SwingScheduler.java
// Worker of RxSwing for RxJava1.x
private final CompositeSubscription innerSubscription = new CompositeSubscription();
@Override
public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) {
//réduction
final BooleanSubscription s = BooleanSubscription.create();
//réduction
innerSubscription.add(s);
// wrap for returning so it also removes it from the 'innerSubscription'
return Subscriptions.create(new Action0() {
@Override
public void call() {
timer.stop();
s.unsubscribe();
innerSubscription.remove(s);
}
});
}
@Override
public void unsubscribe() {
innerSubscription.unsubscribe();
}
@Override
public boolean isUnsubscribed() {
return innerSubscription.isUnsubscribed();
}
Appelons RxSwing pour RxJava1.x RxSwing1. Dans RxSwing1, les deux ʻunsubscribe () `sont différents comme décrit ci-dessus.
à l'instance
Worker`à l'instance
Subscription renvoyée par
schedule () de l'instance
Worker`Travailleur
Par exemple, il est possible que RxJava2.x ait changé ce qui est exigé de Woker. Pour savoir ce qui est juste, jetez un œil à notre Jake God RxAndroid.
// Worker of RxAndroid for RxJava2.x
private volatile boolean disposed;
@Override
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
//réduction
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
Message message = Message.obtain(handler, scheduled);
message.obj = this; // Used as token for batch disposal of this worker's runnables.
handler.sendMessageDelayed(message, Math.max(0L, unit.toMillis(delay)));
//réduction
return scheduled;
}
@Override
public void dispose() {
disposed = true;
handler.removeCallbacksAndMessages(this /* token */);
}
@Override
public boolean isDisposed() {
return disposed;
}
private static final class ScheduledRunnable implements Runnable, Disposable {
private final Handler handler;
private final Runnable delegate;
private volatile boolean disposed;
ScheduledRunnable(Handler 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() {
disposed = true;
handler.removeCallbacks(this);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
Dans RxAndroid, qui devrait prendre en charge RxJava 2.x comme ceci, Les deux opérations suivantes ne sont pas égales.
dispose ()
vers l'instanceWorker
dispose ()
à l'instanceDisposable
renvoyée parschedule ()
de l'instanceWorker
Donc, le fait que les deux «dispose ()» soient égaux est susceptible de poser problème. Cependant, je n'ai pas trouvé de modèle d'utilisation. Il est préférable de montrer le bien ou le mal quel que soit le nombre d'utilisateurs de RxAndroid et la croyance en Jake God. Je suis à court de pouvoir et d'intérêt ici.
Scheduler
correspondant à RxJava 2.xalors,
"Dans un cas, vous pouvez appeler schedule ()
pour chaque tâche et` dispose () ʻindividuellement. "
Je pense qu'il est de la responsabilité du «planificateur» de renvoyer un tel «travailleur».
Sur la base de ce qui précède, il s'agit d'un exemple d'implémentation de RxSwing Scheduler
correspondant à RxJava 2.x.
https://github.com/guignol/SwingBinding/blob/05913b51d9aa6daf8cb0aa3113c699f23879c77e/src/main/java/com/github/guignol/swing/rx/SwingScheduler.java
public class SwingScheduler extends Scheduler {
private static final SwingScheduler INSTANCE = new SwingScheduler();
public static SwingScheduler getInstance() {
return INSTANCE;
}
private SwingScheduler() {
}
@Override
public Disposable scheduleDirect(Runnable run) {
//Pourquoi TODO Rx Android remplace cela
//TODO Si vous le laissez tel quel, est-il possible qu'il soit éliminé par Disposable Task?
return super.scheduleDirect(run);
}
@Override
public Worker createWorker() {
return new InnerSwingScheduler();
}
private static class InnerSwingScheduler extends Worker {
private final CompositeDisposable composite = new CompositeDisposable();
@Override
public Disposable schedule(Runnable original, long delayTime, TimeUnit unit) {
if (original == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
final long delay = Math.max(0, unit.toMillis(delayTime));
assertThatTheDelayIsValidForTheSwingTimer(delay);
final Disposable local;
if (delay == 0) {
local = Disposables.empty();
if (SwingUtilities.isEventDispatchThread()) {
//Exécution immédiate
original.run();
} else {
SwingUtilities.invokeLater(() -> {
if (composite.isDisposed() || local.isDisposed()) {
return;
}
original.run();
composite.remove(local);
});
}
} else {
final Timer timer = new Timer((int) delay, null);
local = Disposables.fromRunnable(timer::stop);
timer.setRepeats(false);
timer.addActionListener(e -> {
if (composite.isDisposed() || local.isDisposed()) {
return;
}
original.run();
composite.remove(local);
});
timer.start();
}
composite.add(local);
//Le Swing Scheduler d'Ueli Kurmann retourne un jetable composite pour ouvrier et ne peut pas se débarrasser tâche par tâche
//Android Scheduler fournit également une élimination basée sur les tâches, donc je pense que c'est nécessaire, mais je n'ai pas trouvé de modèle d'utilisation qui fasse une différence.
return local;
}
@Override
public void dispose() {
composite.dispose();
}
@Override
public boolean isDisposed() {
return composite.isDisposed();
}
private static void assertThatTheDelayIsValidForTheSwingTimer(long delay) {
if (delay < 0 || delay > Integer.MAX_VALUE) {
throw new IllegalArgumentException(String.format("The swing timer only accepts non-negative delays up to %d milliseconds.", Integer.MAX_VALUE));
}
}
}
}
C'est un petit code, mais Il existe un exemple appelé RxAndroid, il existe un exemple d'implémentation appelé RxSwing, C'était une tâche amusante.
doOnDispose
Il y a d'autres mystères qui m'intéressent à propos de Scheduler, mais c'est tout pour cet article. Merci pour votre travail.
*1
En fait, RxAndroid est une bibliothèque qui fournit un Scheduler. Il semble que RxSwing2 puisse être publié si une telle politique est adoptée.
*2
Il ne fonctionne pas sur la JVM, alors c'est tout, Zygote fourche le processus de l'application et l'exécute en premier dans la méthode main () de la classe ActivtyThread. Ici, la boucle d'événements qui devient le thread d'interface utilisateur tourne autour. Par conséquent, il est identique au thread principal de Java. Pour plus d'informations sur ce domaine, lisez «Technologies prenant en charge Android». Allez parce que c'est le meilleur. https://www.amazon.co.jp/dp/4774187593
Recommended Posts