You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
2.4 KiB
Java
80 lines
2.4 KiB
Java
package com.fox2code.mmm.utils;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
/**
|
|
* Manager that want both to be thread safe and not to worry about thread safety
|
|
* {@link #scan()} and {@link #update(UpdateListener)} can be called from multiple
|
|
* thread at the same time, {@link #scanInternal(UpdateListener)} will only be
|
|
* called from one thread at a time only.
|
|
*/
|
|
public abstract class SyncManager {
|
|
private static final UpdateListener NO_OP = value -> {};
|
|
protected final Object syncLock = new Object();
|
|
private boolean syncing;
|
|
private long lastSync;
|
|
|
|
public final void scanAsync() {
|
|
if (!this.syncing) {
|
|
new Thread(this::scan, "Scan Thread").start();
|
|
}
|
|
}
|
|
|
|
public final void scan() {
|
|
this.update(null);
|
|
}
|
|
|
|
// MultiThread friendly method
|
|
public final void update(@Nullable UpdateListener updateListener) {
|
|
if (updateListener == null) updateListener = NO_OP;
|
|
if (!this.syncing) {
|
|
// Do scan
|
|
synchronized (this.syncLock) {
|
|
if (System.currentTimeMillis() < this.lastSync + 50L)
|
|
return; // Skip sync if it was synced too recently
|
|
this.syncing = true;
|
|
try {
|
|
this.scanInternal(updateListener);
|
|
} finally {
|
|
this.lastSync = System.currentTimeMillis();
|
|
this.syncing = false;
|
|
}
|
|
}
|
|
} else {
|
|
// Wait for current scan
|
|
synchronized (this.syncLock) {
|
|
Thread.yield();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pause execution until the scan is completed if one is currently running
|
|
public final void afterScan() {
|
|
if (this.syncing) synchronized (this.syncLock) { Thread.yield(); }
|
|
}
|
|
|
|
public final void runAfterScan(Runnable runnable) {
|
|
synchronized (this.syncLock) {
|
|
runnable.run();
|
|
}
|
|
}
|
|
|
|
public final void afterUpdate() {
|
|
if (this.syncing) synchronized (this.syncLock) { Thread.yield(); }
|
|
}
|
|
|
|
public final void runAfterUpdate(Runnable runnable) {
|
|
synchronized (this.syncLock) {
|
|
runnable.run();
|
|
}
|
|
}
|
|
|
|
// This method can't be called twice at the same time.
|
|
protected abstract void scanInternal(@NonNull UpdateListener updateListener);
|
|
|
|
public interface UpdateListener {
|
|
void update(double value);
|
|
}
|
|
}
|