/** * Copyright (C) 2010-2016 eBusiness Information, Excilys Group * Copyright (C) 2016-2020 the AndroidAnnotations project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed To in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.androidannotations.api; import java.util.HashMap; import java.util.Map; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; /** * This class provide operations for * {@link org.androidannotations.annotations.UiThread UiThread} tasks. */ public final class UiThreadExecutor { private static final Handler HANDLER = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { Runnable callback = msg.getCallback(); if (callback != null) { callback.run(); decrementToken((Token) msg.obj); } else { super.handleMessage(msg); } } }; private static final Map TOKENS = new HashMap<>(); private UiThreadExecutor() { // should not be instantiated } /** * Store a new task in the map for providing cancellation. This method is used * by AndroidAnnotations and not intended to be called by clients. * * @param id * the identifier of the task * @param task * the task itself * @param delay * the delay or zero to run immediately */ public static void runTask(String id, Runnable task, long delay) { if ("".equals(id)) { HANDLER.postDelayed(task, delay); return; } long time = SystemClock.uptimeMillis() + delay; HANDLER.postAtTime(task, nextToken(id), time); } private static Token nextToken(String id) { synchronized (TOKENS) { Token token = TOKENS.get(id); if (token == null) { token = new Token(id); TOKENS.put(id, token); } token.runnablesCount++; return token; } } private static void decrementToken(Token token) { synchronized (TOKENS) { if (--token.runnablesCount == 0) { String id = token.id; Token old = TOKENS.remove(id); if (old != token) { // a runnable finished after cancelling, we just removed a // wrong token, lets put it back TOKENS.put(id, old); } } } } /** * Cancel all tasks having the specified id. * * @param id * the cancellation identifier */ public static void cancelAll(String id) { Token token; synchronized (TOKENS) { token = TOKENS.remove(id); } if (token == null) { // nothing to cancel return; } HANDLER.removeCallbacksAndMessages(token); } private static final class Token { int runnablesCount = 0; final String id; private Token(String id) { this.id = id; } } }