diff --git a/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/UiThread.java b/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/UiThread.java index 39b94bde2e..20839d689e 100644 --- a/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/UiThread.java +++ b/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/UiThread.java @@ -31,4 +31,18 @@ @Target(ElementType.METHOD) public @interface UiThread { long delay() default 0; + + /** + * If propagation = REUSE, the method will check first if it is inside the + * UI thread already. If so, it will directly call the method instead of + * using the handler. The default value is ENQUEUE, which will always call + * the handler. + * + * @return + */ + Propagation propagation() default Propagation.ENQUEUE; + + public enum Propagation { + ENQUEUE, REUSE + } } diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/UiThreadProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/UiThreadProcessor.java index 16e1c00c59..1b4e78caf7 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/UiThreadProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/UiThreadProcessor.java @@ -22,18 +22,29 @@ import javax.lang.model.element.ExecutableElement; import org.androidannotations.annotations.UiThread; +import org.androidannotations.annotations.UiThread.Propagation; import org.androidannotations.helper.APTCodeModelHelper; +import android.os.Looper; + +import com.sun.codemodel.JBlock; import com.sun.codemodel.JClass; import com.sun.codemodel.JClassAlreadyExistsException; import com.sun.codemodel.JCodeModel; +import com.sun.codemodel.JConditional; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JExpr; +import com.sun.codemodel.JExpression; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; +import com.sun.codemodel.JOp; public class UiThreadProcessor implements DecoratingElementProcessor { + private static final String METHOD_CUR_THREAD = "currentThread"; + private static final String METHOD_MAIN_LOOPER = "getMainLooper"; + private static final String METHOD_GET_THREAD = "getThread"; + private final APTCodeModelHelper helper = new APTCodeModelHelper(); @Override @@ -45,6 +56,8 @@ public String getTarget() { public void process(Element element, JCodeModel codeModel, EBeanHolder holder) throws JClassAlreadyExistsException { ExecutableElement executableElement = (ExecutableElement) element; + UiThread annotation = element.getAnnotation(UiThread.class); + Propagation propagation = annotation.propagation(); JMethod delegatingMethod = helper.overrideAnnotatedMethod(executableElement, holder); @@ -52,8 +65,6 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) t { // Execute Runnable - - UiThread annotation = element.getAnnotation(UiThread.class); long delay = annotation.delay(); if (holder.handler == null) { @@ -62,6 +73,11 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) t } if (delay == 0) { + if (propagation == Propagation.REUSE) { + // Put in the check for the UI thread. + addUIThreadCheck(delegatingMethod, codeModel, holder); + } + delegatingMethod.body().invoke(holder.handler, "post").arg(_new(anonymousRunnableClass)); } else { delegatingMethod.body().invoke(holder.handler, "postDelayed").arg(_new(anonymousRunnableClass)).arg(lit(delay)); @@ -70,4 +86,29 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) t } + /** + * Add the pre-check to see if we are already in the UI thread. + * + * @param delegatingMethod + * @param codeModel + * @param holder + * @throws JClassAlreadyExistsException + */ + private void addUIThreadCheck(JMethod delegatingMethod, JCodeModel codeModel, EBeanHolder holder) throws JClassAlreadyExistsException { + // Get the Thread and Looper class. + JClass tClass = codeModel.ref(Thread.class); + JClass lClass = codeModel.ref(Looper.class); + + // invoke the methods. + JExpression lhs = tClass.staticInvoke(METHOD_CUR_THREAD); + JExpression rhs = lClass.staticInvoke(METHOD_MAIN_LOOPER).invoke(METHOD_GET_THREAD); + + // create the conditional and the block. + JConditional con = delegatingMethod.body()._if(JOp.eq(lhs, rhs)); + JBlock thenBlock = con._then(); + + helper.callSuperMethod(delegatingMethod, holder, thenBlock); + + thenBlock._return(); + } }