SerialSingleThreadExecutor.java

 1package eu.siacs.conversations.utils;
 2
 3import android.os.Looper;
 4import android.util.Log;
 5
 6import java.util.ArrayDeque;
 7import java.util.Queue;
 8import java.util.concurrent.Executor;
 9import java.util.concurrent.Executors;
10
11import eu.siacs.conversations.Config;
12import eu.siacs.conversations.services.AttachFileToConversationRunnable;
13
14public class SerialSingleThreadExecutor implements Executor {
15
16	private final Executor executor = Executors.newSingleThreadExecutor();
17	final ArrayDeque<Runnable> tasks = new ArrayDeque<>();
18	protected Runnable active;
19	private final String name;
20
21	public SerialSingleThreadExecutor(String name) {
22		this(name, false);
23	}
24
25	SerialSingleThreadExecutor(String name, boolean prepareLooper) {
26		if (prepareLooper) {
27			execute(Looper::prepare);
28		}
29		this.name = name;
30	}
31
32	public synchronized void execute(final Runnable r) {
33		tasks.offer(new Runner(r));
34		if (active == null) {
35			scheduleNext();
36		}
37	}
38
39	private synchronized void scheduleNext() {
40		if ((active = tasks.poll()) != null) {
41			executor.execute(active);
42			int remaining = tasks.size();
43			if (remaining > 0) {
44				Log.d(Config.LOGTAG,remaining+" remaining tasks on executor '"+name+"'");
45			}
46		}
47	}
48
49	private class Runner implements Runnable, Cancellable {
50
51		private final Runnable runnable;
52
53		private Runner(Runnable runnable) {
54			this.runnable = runnable;
55		}
56
57		@Override
58		public void cancel() {
59			if (runnable instanceof Cancellable) {
60				((Cancellable) runnable).cancel();
61			}
62		}
63
64		@Override
65		public void run() {
66			try {
67				runnable.run();
68			} finally {
69				scheduleNext();
70			}
71		}
72	}
73}