1515 */
1616package org .androidannotations .api ;
1717
18- import java .util .Collections ;
19- import java .util .Set ;
2018import java .util .concurrent .ConcurrentHashMap ;
21- import java .util .concurrent .ConcurrentLinkedQueue ;
22- import java .util .concurrent .atomic .AtomicInteger ;
2319
2420import android .os .Handler ;
2521import android .os .Looper ;
22+ import android .os .SystemClock ;
2623
2724/**
2825 * This class provide operations for
@@ -32,13 +29,7 @@ public class UiThreadExecutor {
3229
3330 private static final Handler HANDLER = new Handler (Looper .getMainLooper ());
3431
35- private static final ConcurrentHashMap <String , Set <Runnable >> TASKS = new ConcurrentHashMap <String , Set <Runnable >>();
36-
37- private static final Set <Runnable > JUST_POSTED_TASKS = Collections .newSetFromMap (new ConcurrentHashMap <Runnable , Boolean >());
38-
39- private static final ConcurrentLinkedQueue <Set <Runnable >> ALLOCATION_STASH = new ConcurrentLinkedQueue <Set <Runnable >>();
40- private static final AtomicInteger ALLOCATION_STASH_SIZE = new AtomicInteger (0 );
41- private static final int ALLOCATION_STASH_MAX_SIZE = 16 ;
32+ private static final ConcurrentHashMap <String , Object > TOKENS = new ConcurrentHashMap <String , Object >();
4233
4334 private UiThreadExecutor () {
4435 // should not be instantiated
@@ -60,57 +51,21 @@ public static void runTask(String id, Runnable task, long delay) {
6051 HANDLER .postDelayed (task , delay );
6152 return ;
6253 }
63- JUST_POSTED_TASKS .add (task );
64- HANDLER .postDelayed (task , delay );
65-
66- Set <Runnable > runnables = TASKS .get (id );
67- if (runnables == null ) {
68- runnables = allocateRunnables ();
69- runnables .add (task );
70-
71- while (true ) {
72- Set <Runnable > oldRunnables = TASKS .putIfAbsent (id , runnables );
73- if (oldRunnables != null ) {
74- if (oldRunnables .isEmpty ()) {
75- // it is about to be removed - lets try to replace it
76- if (!TASKS .replace (id , oldRunnables , runnables )) {
77- // it is already has bean replaced by different
78- // thread - lets try again
79- continue ;
80- }
81- } else {
82- recycle (runnables );
83- oldRunnables .add (task );
84- }
85- }
86- break ;
87- }
88- } else {
89- runnables .add (task );
90- }
91-
92- // if the task has already been completed - make sure to clean up
93- if (!JUST_POSTED_TASKS .remove (task )) {
94- done (id , task );
95- }
96- }
97-
98- private static Set <Runnable > allocateRunnables () {
99- Set <Runnable > runnables = ALLOCATION_STASH .poll ();
100- if (runnables != null ) {
101- ALLOCATION_STASH_SIZE .getAndDecrement ();
102- return runnables ;
103- }
104- return Collections .newSetFromMap (new ConcurrentHashMap <Runnable , Boolean >());
54+ long time = SystemClock .uptimeMillis () + delay ;
55+ HANDLER .postAtTime (task , getToken (id ), time );
10556 }
10657
107- private static void recycle (Set <Runnable > runnables ) {
108- if (ALLOCATION_STASH_SIZE .getAndIncrement () < ALLOCATION_STASH_MAX_SIZE ) {
109- runnables .clear ();
110- ALLOCATION_STASH .offer (runnables );
111- } else {
112- ALLOCATION_STASH_SIZE .getAndDecrement ();
58+ private static Object getToken (String id ) {
59+ Object token = TOKENS .get (id );
60+ if (token == null ) {
61+ token = new Object ();
62+ Object oldObject = TOKENS .putIfAbsent (id , token );
63+ // if a concurrent thread was faster
64+ if (oldObject != null ) {
65+ token = oldObject ;
66+ }
11367 }
68+ return token ;
11469 }
11570
11671 /**
@@ -120,35 +75,12 @@ private static void recycle(Set<Runnable> runnables) {
12075 * the cancellation identifier
12176 */
12277 public static void cancelAll (String id ) {
123- Set <Runnable > runnables = TASKS .remove (id );
124- if (runnables != null ) {
125- for (Runnable runnable : runnables ) {
126- HANDLER .removeCallbacks (runnable );
127- }
128- recycle (runnables );
129- }
130- }
131-
132- /**
133- * Should be called after the task has been executed. It is ok to call it
134- * more then once for the case of cleaning up.
135- *
136- * @param id
137- * the task id
138- * @param runnable
139- * the task itself
140- */
141- public static void done (String id , Runnable runnable ) {
142- JUST_POSTED_TASKS .remove (runnable );
143- Set <Runnable > runnables = TASKS .get (id );
144- if (runnables != null ) {
145- if (runnables .remove (runnable )) {
146- if (runnables .isEmpty ()) { // if it is empty
147- TASKS .remove (id , runnables );
148- recycle (runnables );
149- }
150- }
78+ Object token = TOKENS .get (id );
79+ if (token == null ) {
80+ // nothing to cancel
81+ return ;
15182 }
83+ HANDLER .removeCallbacksAndMessages (token );
15284 }
15385
15486}
0 commit comments